diff --git a/source-code/Poisson-Graphs/Blockchain.py b/source-code/Poisson-Graphs/Blockchain.py index f0e23c5..17808e3 100644 --- a/source-code/Poisson-Graphs/Blockchain.py +++ b/source-code/Poisson-Graphs/Blockchain.py @@ -1,4 +1,8 @@ from Block import * +import math +from scipy.stats import * +from numpy import * +from copy import deepcopy class Blockchain(object): ''' @@ -10,21 +14,26 @@ class Blockchain(object): self.blocks = {} self.leaves = {} self.miningIdents = None + self.mIdent = None self.verbose = verbosity + self.diff = None + self.targetRate = None + self.mode = None def addBlock(self, blockToAdd): # In our model we assume difficulty scores of blocks are correct (otherwise they would # be rejected in the real life network, and we aren't trying to model spam attacks). - try: - assert blockToAdd.ident not in self.blocks - except AssertionError: - print("Error, tried to add block that already exists in blockchain.") - else: - self.blocks.update({blockToAdd.ident:blockToAdd}) - self.leaves.update({blockToAdd.ident:blockToAdd}) - if blockToAdd.parent in self.leaves: - del self.leaves[blockToAdd.parent] - self.whichLeaf() + assert blockToAdd.ident not in self.blocks + if len(self.blocks)==0: + # In this case, blockToAdd is a genesis block, so we set difficulty + self.diff = deepcopy(blockToAdd.diff) + + self.blocks.update({blockToAdd.ident:blockToAdd}) + self.leaves.update({blockToAdd.ident:blockToAdd}) + if blockToAdd.parent in self.leaves: + del self.leaves[blockToAdd.parent] + self.whichLeaf() + return self.computeDifficulty() def whichLeaf(self): # Determine which leaf shall be the parent leaf. @@ -52,10 +61,217 @@ class Blockchain(object): self.miningIdents.append(ident) #print("leaf ident = ", str(ident), ", and tempCumDiff = ", str(tempCumDiff), " and maxCumDiff = ", str(maxCumDiff)) assert len(self.miningIdents) > 0 + self.mIdent = random.choice(self.miningIdents) + + + # 1 block in 6*10^5 milliseconds=10min + def computeDifficulty(self): + result = None + if self.mode=="Nakamoto": + # Use MLE estimate of poisson process, compare to targetRate, update by multiplying by resulting ratio. + #if self.verbose: + # print("Beginning update of difficulty with Nakamoto method") + count = 2016 + #if self.verbose: + # print("Checking that blockchain is 2016*n blocks long and some mining identity has been set") + if len(self.blocks) % 2016 == 0 and len(self.miningIdents) > 0: + ident = self.mIdent + topTime = deepcopy(self.blocks[ident].discoTimestamp) + parent = self.blocks[ident].parent + count = count - 1 + touched = False + while count > 0 and parent is not None: + ident = deepcopy(parent) + parent = self.blocks[ident].parent + count = count - 1 + touched = True + if not touched: + mleDiscoRate = deepcopy(self.targetRate) + else: + botTime = deepcopy(self.blocks[ident].discoTimestamp) + + # Algebra is okay: + assert topTime != botTime + + # MLE estimate of arrivals per second: + mleDiscoRate = float(2015)/float(topTime - botTime) + + # Rates can't be negative, but this estimate could be (although it's highly unlikely given Bitcoin's standard choices + # of difficulty update rate, etc. + mleDiscoRate = abs(mleDiscoRate) + + if self.verbose: + print("MLE disco rate = " + str(mleDiscoRate) + " and targetRate = " + str(self.targetRate)) + # Rate must be positive... so the MLE for block arrival rate + # assuming a Poisson process _is not even well-defined_ as + # an estimate for block arrival rate assuming timestamps are + # inaccurately reported! + + # We use it nonetheless. + + if self.verbose: + print("MLE discovery rate = " + str(mleDiscoRate)) + print("Difficulty before adjustment = " + str(self.diff)) + + # Update difficulty multiplicatively + self.diff = self.diff*mleDiscoRate/self.targetRate + + if self.verbose: + print("Difficulty after adjustment = ", str(self.diff)) + + elif self.mode=="vanSaberhagen": + # Similar to above, except use 1200 blocks, discard top 120 and bottom 120 after sorting. + # 4 minute blocks in the original cryptonote, I believe... targetRate = 1.0/ + # 4 minutes/period, 60 seconds/minute ~ 240 seconds/period + # assert targetRate==1.0/240.0 + count = 1200 + #print(self.diff) + assert self.diff != 0.0 + if len(self.blocks) > 120 and len(self.miningIdents) > 0: + ident = self.mIdent + bl = [] + bl.append(deepcopy(self.blocks[ident].discoTimestamp)) + parent = self.blocks[ident].parent + count = count - 1 + while count > 0 and parent is not None: + ident = deepcopy(parent) + bl.append(deepcopy(self.blocks[ident].discoTimestamp)) + parent = self.blocks[ident].parent + count = count-1 + # sort + bl = sorted(bl) + assert len(bl)<=1200 + + #print("Sample size = " + str(len(bl))) + # remove 10 and 90 %-iles + numOutliers = math.ceil(float(len(bl))/float(10)) + assert numOutliers <= 120 + #print("Number of outliers = " + str(numOutliers)) + oldBL = deepcopy(bl) + if numOutliers > 0: + bl = bl[numOutliers:-numOutliers] + #if numOutliers == 120: + # print("\n\nSORTED TS LIST = " + str(oldBL) + "\nModified list = " + str(bl)) + + + # get topTime and botTime + #if self.verbose: + # print("bl[0] = " + str(bl[0]) + ",\tbl[-1] = " + str(bl[-1])) + topTime = bl[-1] + botTime = bl[0] + result = [float(topTime - botTime)] + #print(topTime - botTime) + #if self.verbose: + # print("list of timestamps = " + str(bl)) + # print("topTime = " + str(bl[-1])) + # print("botTime = " + str(bl[0])) + + # Assert algebra will work + # 1200 - 2*120 = 1200 - 240 = 960 + assert 0 < len(bl) and len(bl) < 961 + assert topTime - botTime >= 0.0 + result.append(len(bl)-1) + # Sort of the MLE: # blocks/difference in reported times + # But not the MLE, since the reported times may not be + # the actual times, the "difference in reported times" != + # "ground truth difference in block discoery times" in general + if len(bl)==0: + print("WOOP WOOP NO TIMESTAMPS WTF? We have " + str(len(self.blocks)) + " blocks available, and we are counting " + str(2*numOutliers) + " as outliers. bl = " + str(bl)) + naiveDiscoRate = float(len(bl)-1)/float(topTime - botTime) + + # How much should difficulty change? + assert naiveDiscoRate != 0.0 + assert self.targetRate != 0.0 + assert self.diff != 0.0 + self.diff = self.diff*naiveDiscoRate/self.targetRate + + elif self.mode=="MOM:expModGauss": + # Similar to "vanSaberhagen" except with 2-minute blocks and + # we attempt to take into account that "difference in timestamps" + # can be negative by: + # 1) insisting that the ordering induced by the blockchain and + # 2) modeling timestamps as exponentially modified gaussian. + # If timestamps are T = X + Z where X is exponentially dist- + # ributed with parameter lambda and Z is some Gaussian + # noise with average mu and variance sigma2, then we can est- + # imate sigma2, mu, and lambda: + # mu ~ mean - stdev*(skewness/2)**(1.0/3.0) + # sigma2 ~ variance*(1-(skewness/2)**(2.0/3.0)) + # lambda ~ (1.0/(stdev))*(2/skewness)**(1.0/3.0) + #assert targetRate==1.0/120.0 + + # Really a trash metric unless sample sizes are huge. + count = 1200 + ident = self.mIdent + bl = [] + bl.append(deepcopy(self.blocks[ident].discoTimestamp)) + parent = self.blocks[ident].parent + count = count - 1 + while count > 0 and parent is not None: + ident = deepcopy(parent) + bl.append(deepcopy(self.blocks[ident].discoTimestamp)) + parent = self.blocks[ident].parent + count = count-1 + if len(bl) > 120: + sk = abs(skew(bl)) + va = var(bl) + stdv = sqrt(va) + lam = (1.0/stdv)*(2.0/sk)**(1.0/3.0) + else: + lam = self.targetRate # we will not change difficulty unless we have at least 120 blocks of data (arbitrarily selected) + self.diff = self.diff*(lam/self.targetRate) + elif self.mode=="reciprocalOfMedian": + # In this mode we use a bitcoin-style metric except instead of 1/average inter-arrival time + # we use 1/median magnitude of inter-arrival time. + # And updated each block like with monero instead of every 2016 blocks like bitcoin. + # We assume a sample size of only 600 blocks for now + count = 600 + interArrivals = [] + if len(self.blocks) < count: + estDiscoRate = self.targetRate + elif len(self.miningIdents) > 0: + ident = self.mIdent + parent = self.blocks[ident].parent + if parent is not None: + dT = abs(self.blocks[ident].discoTimestamp - self.blocks[parent].discoTimestamp) + interArrivals.append(dT) + count = count - 1 + touched = False + while count > 0 and parent is not None: + ident = deepcopy(parent) + parent = self.blocks[ident].parent + if parent is not None: + dT = abs(self.blocks[ident].discoTimestamp - self.blocks[parent].discoTimestamp) + interArrivals.append(dT) + count = count - 1 + touched = True + if not touched: + estDiscoRate = self.targetRate + else: + estDiscoRate = 1.0/median(interArrivals) + if self.verbose: + print("Est disco rate = " + str(estDiscoRate) + " and targetRate = " + str(self.targetRate)) + + + if self.verbose: + print("MLE discovery rate = " + str(estDiscoRate)) + print("Difficulty before adjustment = " + str(self.diff)) + + # Update difficulty multiplicatively + self.diff = self.diff*estDiscoRate/self.targetRate + + if self.verbose: + print("Difficulty after adjustment = ", str(self.diff)) + else: + print("Error, invalid difficulty mode entered.") + return result class Test_Blockchain(unittest.TestCase): def test_addBlock(self): bill = Blockchain([], verbosity=True) + bill.mode="Nakamoto" + tr = 1.0/100.0 + bill.targetRate = tr name = newIdent(0) t = time.time() @@ -94,8 +310,101 @@ class Test_Blockchain(unittest.TestCase): self.assertEqual(len(bill.blocks),2) + + + + bill = Blockchain([], verbosity=True) + mode="vanSaberhagen" + tr = 1.0/100.0 + bill.targetRate = tr + + name = newIdent(0) + t = time.time() + s = t+random.random() + diff = 1.0 + params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} + genesis = Block(params) + + self.assertEqual(genesis.ident,name) + self.assertEqual(genesis.discoTimestamp,t) + self.assertEqual(genesis.arrivTimestamp,s) + self.assertTrue(genesis.parent is None) + self.assertEqual(genesis.diff,diff) + + bill.addBlock(genesis, mode, tr) + + self.assertTrue(genesis.ident in bill.blocks) + self.assertTrue(genesis.ident in bill.leaves) + self.assertEqual(len(bill.miningIdents),1) + self.assertEqual(genesis.ident, bill.miningIdents[0]) + self.assertEqual(len(bill.blocks),1) + + name = newIdent(1) + t = time.time() + s = t+random.random() + diff = 1.0 + params = {"ident":name, "disco":t, "arriv":s, "parent":genesis.ident, "diff":diff} + blockA = Block(params) + bill.addBlock(blockA, mode, tr) + + self.assertTrue(blockA.ident in bill.blocks) + self.assertTrue(blockA.ident in bill.leaves) + self.assertTrue(genesis.ident not in bill.leaves) + self.assertEqual(len(bill.miningIdents),1) + self.assertEqual(blockA.ident, bill.miningIdents[0]) + self.assertEqual(len(bill.blocks),2) + + + + + + bill = Blockchain([], verbosity=True) + mode="MOM:expModGauss" + tr = 1.0/100.0 + bill.targetRate = tr + + name = newIdent(0) + t = time.time() + s = t+random.random() + diff = 1.0 + params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} + genesis = Block(params) + + self.assertEqual(genesis.ident,name) + self.assertEqual(genesis.discoTimestamp,t) + self.assertEqual(genesis.arrivTimestamp,s) + self.assertTrue(genesis.parent is None) + self.assertEqual(genesis.diff,diff) + + bill.addBlock(genesis, mode, tr) + + self.assertTrue(genesis.ident in bill.blocks) + self.assertTrue(genesis.ident in bill.leaves) + self.assertEqual(len(bill.miningIdents),1) + self.assertEqual(genesis.ident, bill.miningIdents[0]) + self.assertEqual(len(bill.blocks),1) + + name = newIdent(1) + t = time.time() + s = t+random.random() + diff = 1.0 + params = {"ident":name, "disco":t, "arriv":s, "parent":genesis.ident, "diff":diff} + blockA = Block(params) + bill.addBlock(blockA, mode, tr) + + self.assertTrue(blockA.ident in bill.blocks) + self.assertTrue(blockA.ident in bill.leaves) + self.assertTrue(genesis.ident not in bill.leaves) + self.assertEqual(len(bill.miningIdents),1) + self.assertEqual(blockA.ident, bill.miningIdents[0]) + self.assertEqual(len(bill.blocks),2) + + def test_bc(self): bill = Blockchain([], verbosity=True) + mode="Nakamoto" + tr = 1.0/100.0 + bill.targetRate = tr name = newIdent(0) t = time.time() @@ -110,7 +419,7 @@ class Test_Blockchain(unittest.TestCase): self.assertTrue(genesis.parent is None) self.assertEqual(genesis.diff,diff) - bill.addBlock(genesis) + bill.addBlock(genesis, mode, tr) self.assertTrue(genesis.ident in bill.blocks) self.assertTrue(genesis.ident in bill.leaves) @@ -123,9 +432,9 @@ class Test_Blockchain(unittest.TestCase): diff = 2.0 params = {"ident":name, "disco":t, "arriv":s, "parent":genesis.ident, "diff":diff} blockA = Block(params) - bill.addBlock(blockA) + bill.addBlock(blockA, mode, tr) - bill.whichLeaf() + #bill.whichLeaf() self.assertTrue(blockA.ident in bill.blocks) self.assertTrue(blockA.ident in bill.leaves) @@ -140,7 +449,7 @@ class Test_Blockchain(unittest.TestCase): diff = 2.0 params = {"ident":name, "disco":t, "arriv":s, "parent":genesis.ident, "diff":diff} blockB = Block(params) - bill.addBlock(blockB) + bill.addBlock(blockB, mode, tr) self.assertTrue(blockB.ident in bill.blocks) self.assertTrue(blockB.ident in bill.leaves) @@ -154,7 +463,7 @@ class Test_Blockchain(unittest.TestCase): self.assertFalse(genesis.ident in bill.leaves) self.assertTrue(bill.blocks[genesis.ident].parent is None) - bill.whichLeaf() + #bill.whichLeaf() #print(bill.miningIdents) self.assertEqual(type(bill.miningIdents), type([])) @@ -165,7 +474,7 @@ class Test_Blockchain(unittest.TestCase): diff = 3.14159 params = {"ident":name, "disco":t, "arriv":s, "parent":blockB.ident, "diff":diff} blockC = Block(params) - bill.addBlock(blockC) + bill.addBlock(blockC, mode, tr) self.assertTrue(blockC.ident in bill.blocks) self.assertTrue(blockC.ident in bill.leaves) @@ -179,7 +488,7 @@ class Test_Blockchain(unittest.TestCase): self.assertTrue(genesis.ident in bill.blocks) self.assertFalse(genesis.ident in bill.leaves) - bill.whichLeaf() + #bill.whichLeaf() #for blockIdent in bill.blocks: # ident = bill.blocks[blockIdent].ident @@ -191,8 +500,644 @@ class Test_Blockchain(unittest.TestCase): #print(bill.miningIdents) self.assertEqual(len(bill.miningIdents), 1) self.assertEqual(bill.miningIdents[0], blockC.ident) + + def test_median(self): + # TODO: everything. + mode = "reciprocalOfMedian" + tr = 1.0 # one block per millisecond why not + deltaT = 1.0 # let's just make this easy + bill = Blockchain([], verbosity=True) + bill.targetRate = tr + + with open("outputM.txt", "w") as writeFile: + # We will send (t, a, diff) to writeFile. + writeFile.write("time,rateConstant,difficulty\n") + name = newIdent(0) + t = 0.0 + s = 0.0 + diff = 1.0 + params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} + genesis = Block(params) + + self.assertEqual(genesis.ident,name) + self.assertEqual(genesis.discoTimestamp,t) + self.assertEqual(genesis.arrivTimestamp,s) + self.assertTrue(genesis.parent is None) + self.assertEqual(genesis.diff,diff) + + bill.addBlock(genesis, mode, tr) + a = 1.0 + b = 1.0/a + + writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") + + self.assertTrue(genesis.ident in bill.blocks) + self.assertTrue(genesis.ident in bill.leaves) + self.assertEqual(len(bill.miningIdents),1) + self.assertEqual(genesis.ident, bill.miningIdents[0]) + + parent = genesis.ident + oldDiff = bill.diff + + while len(bill.blocks)<601: + newName = newIdent(len(bill.blocks)) + t += deltaT*a + s += deltaT*a + self.assertEqual(bill.diff, oldDiff) + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + bill.addBlock(newBlock, mode, tr) + + writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") + parent = newName + oldDiff = bill.diff + + a = 1.01 # slightly slower blocks, median won't change until half the data is corrupted! + b = 1.0/a + while len(bill.blocks)<899: + newName = newIdent(len(bill.blocks)) + t += deltaT*a + s += deltaT*a + self.assertEqual(bill.diff, oldDiff) + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + bill.addBlock(newBlock, mode, tr) + self.assertEqual(bill.diff, oldDiff) + writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") + parent = newName + oldDiff = bill.diff + + # One more block and our median inter-arrival time is deltaT*(1.0+a)/2.0 + # and so estRate = 1/median = (2.0/(1.0+a))/deltaT, whereas before it was just + # 1/deltaT. So estRate/targetRate = 2.0/(1.0+a) + newName = newIdent(len(bill.blocks)) + t += deltaT*a + s += deltaT*a + self.assertEqual(bill.diff, oldDiff) + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + bill.addBlock(newBlock, mode, tr) + err = bill.diff - oldDiff*2.0/(1.0+a) + self.assertTrue(err*err < 10**-15) + writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") + parent = newName + oldDiff = bill.diff + + # One more block and our median inter-arrival time is deltaT*a + # and so estRate = 1/median = (1.0/a)/deltaT, whereas before it was just + # 1/deltaT. So estRate/targetRate = 1.0/a = b + newName = newIdent(len(bill.blocks)) + t += deltaT*a + s += deltaT*a + self.assertEqual(bill.diff, oldDiff) + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + bill.addBlock(newBlock, mode, tr) + err = bill.diff - oldDiff*b + self.assertTrue(err*err < 10**-15) + writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") + parent = newName + oldDiff = bill.diff + + # Note that until the median changes again, this estimated block arrival rate + # does not change. This may be true even if a lot of new data has come in. + # It is possible that the same pair of blocks remain the median inter-arrival + # magnitude for the entire time both blocks are in the sample size. + # During this period of time, difficulty will update multiplicatively, so + # will either exponentially grow or shrink. + # In other words, this model can be looked at as: exponential change over + # time with a rate proportional to the deviation between the median and + # the target inter-arrival rates. + + + + + + def test_mine(self): + # TODO: everything. + mode = "MOM:expModGauss" + tr = 1.0/120000.0 # one block per two minutes + deltaT = 120000.0 + bill = Blockchain([], verbosity=True) + bill.targetRate = tr + + with open("outputM.txt", "w") as writeFile: + # We will send (t, a, diff, ratio, awayFromOne) to writeFile. + writeFile.write("time,rateConstant,difficulty\n") + name = newIdent(0) + t = 0.0 + s = 0.0 + diff = 1.0 + params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} + genesis = Block(params) + + self.assertEqual(genesis.ident,name) + self.assertEqual(genesis.discoTimestamp,t) + self.assertEqual(genesis.arrivTimestamp,s) + self.assertTrue(genesis.parent is None) + self.assertEqual(genesis.diff,diff) + + bill.addBlock(genesis, mode, tr) + a = 1.0 + b = 1.0/a + + writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") + + self.assertTrue(genesis.ident in bill.blocks) + self.assertTrue(genesis.ident in bill.leaves) + self.assertEqual(len(bill.miningIdents),1) + self.assertEqual(genesis.ident, bill.miningIdents[0]) + + parent = genesis.ident + oldDiff = bill.diff + + while len(bill.blocks)<120: + # Our metric divides by skewness. In reality, this is zero with + # probability zero. But for our tests, it's assured. So we + # will perturb each arrival by a small, up-to-half-percent + # variation to ensure a nonzero skewness without altering things + # too much. + newName = newIdent(len(bill.blocks)) + t += deltaT*a*(1.0 + (2.0*random.random() - 1.0)/100.0) + s += deltaT*a*(1.0 + (2.0*random.random() - 1.0)/100.0) + self.assertEqual(bill.diff, oldDiff) + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + bill.addBlock(newBlock, mode, tr) + + writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") + parent = newName + oldDiff = bill.diff + + # Just one more block and difficulty should be computed for the first time. + print("Just one more block and difficulty should be computed for the first time.") + self.assertEqual(bill.diff, oldDiff) + newName = newIdent(len(bill.blocks)) + t += deltaT*a*(1.0 + (2.0*random.random() - 1.0)/100.0) + s += deltaT*a*(1.0 + (2.0*random.random() - 1.0)/100.0) + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + bill.addBlock(newBlock, mode, tr) + writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") + parent = newName + #self.assertEqual(bill.diff, oldDiff) + + oldDiff = bill.diff + + # what if we add a bunch of blocks this way? + # In the case of a static hash rate, I suppose we hope to not + # vary too far from a multiplicative factor of 1.0, or rather + # a constant difficulty. + + while len(bill.blocks)<200: + # Our metric divides by skewness. In reality, this is zero with + # probability zero. But for our tests, it's assured. So we + # will perturb each arrival by a small, up-to-half-percent + # variation to ensure a nonzero skewness without altering things + # too much. + newName = newIdent(len(bill.blocks)) + t += deltaT*a*(1.0 + (2.0*random.random() - 1.0)/100.0) + s += deltaT*a*(1.0 + (2.0*random.random() - 1.0)/100.0) + self.assertEqual(bill.diff, oldDiff) + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + bill.addBlock(newBlock, mode, tr) + + writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") + parent = newName + oldDiff = bill.diff + + + + def test_vs(self): + # TODO: Still must test that outliers are being removed "appropriately" according to specifications + # TODO: Test that scrambled lists of timestamps produce the same difficulty estimate. + # TODO: Show that in the case of homogeneous poisson processes, unusual estimates are a little + # more common than in the Nakamoto difficulty (which must be the case because Nakamoto uses + # the UMVUE). + mode = "vanSaberhagen" + tr = 1.0/60000.0 # one block per minute + deltaT = 60000.0 + bill = Blockchain([], verbosity=True) + bill.targetRate = tr + + with open("output.txt", "w") as writeFile: + # We will send (t, a, diff, ratio, awayFromOne) to writeFile. + writeFile.write("time,rateConstant,difficulty,ratio\n") + name = newIdent(0) + t = 0.0 + s = 0.0 + diff = 1.0 + params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} + genesis = Block(params) + + self.assertEqual(genesis.ident,name) + self.assertEqual(genesis.discoTimestamp,t) + self.assertEqual(genesis.arrivTimestamp,s) + self.assertTrue(genesis.parent is None) + self.assertEqual(genesis.diff,diff) + + bill.addBlock(genesis, mode, tr) + writeFile.write(str(t) + ",1.0," + str(bill.diff) + ",1.0\n") + + self.assertTrue(genesis.ident in bill.blocks) + self.assertTrue(genesis.ident in bill.leaves) + self.assertEqual(len(bill.miningIdents),1) + self.assertEqual(genesis.ident, bill.miningIdents[0]) + self.assertEqual(bill.diff, 1.0) + + parent = genesis.ident + oldDiff = bill.diff + a = 1.0 + b = 1.0/a + + while len(bill.blocks)<120: + newName = newIdent(len(bill.blocks)) + t += deltaT*a + s += deltaT*a + self.assertEqual(bill.diff, oldDiff) + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + bill.addBlock(newBlock, mode, tr) + + writeFile.write(str(t) + ",1.0," + str(bill.diff) + ",1.0\n") + parent = newName + oldDiff = bill.diff + + # Just one more block and difficulty should be computed for the first time. + print("Just one more block and difficulty should be computed for the first time.") + self.assertEqual(bill.diff, oldDiff) + newName = newIdent(len(bill.blocks)) + t += deltaT*a + s += deltaT*a + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + bill.addBlock(newBlock, mode, tr) + writeFile.write(str(t) + ",1.0," + str(bill.diff) + ",1.0\n") + parent = newName + self.assertEqual(bill.diff, oldDiff) + + oldDiff = bill.diff + + print("Let's add more blocks at the same rate.") + a = 1.0 + b = 1.0/a + + while len(bill.blocks)<1200: + newName = newIdent(len(bill.blocks)) + t += deltaT*a + s += deltaT*a + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + + bill.addBlock(newBlock, mode, tr) + writeFile.write(str(t) + ",1.0," + str(bill.diff) + ",1.0\n") + parent = newName + self.assertEqual(bill.diff, oldDiff) + oldDiff = bill.diff + + print("Let's add more blocks at a slower rate.") + a = 1.1 + b = 1.0/a + + # If blocks arrive slightly further apart, difficulty should drop. + # However, since vanSaberhagen discards top 10% and bottom 10% of + # timestamps, it will take 120 blocks for this change to register + # in difficulty. + print("If blocks arrive slightly further apart, difficulty should drop. However, since vanSaberhagen discards top 10% and bottom 10% of timestamps, it will take 120 blocks for this change to register in difficulty.") + while len(bill.blocks)<1320: + newName = newIdent(len(bill.blocks)) + t += deltaT*a + s += deltaT*a + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + + bill.addBlock(newBlock, mode, tr) + writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "," + str(bill.diff/oldDiff) + "\n") + parent = newName + self.assertEqual(bill.diff, oldDiff) + oldDiff = bill.diff + + print("One more block and difficulty should register a change.") + self.assertEqual(bill.diff, oldDiff) + newName = newIdent(len(bill.blocks)) + t += deltaT*a + s += deltaT*a + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + bill.addBlock(newBlock, mode, tr) + writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "," + str(bill.diff/oldDiff) + "\n") + parent = newName + self.assertTrue(bill.diff < oldDiff) + oldDiff = bill.diff + + # Let's add another fifty blocks at this same rate and verify that difficulty continually + # drops. + print("Let's add another fifty blocks at this same rate and verify that difficulty continually drops.") + a = 1.1 + b = 1.0/a + + while len(bill.blocks)<1370: + newName = newIdent(len(bill.blocks)) + t += deltaT*a + s += deltaT*a + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + + bill.addBlock(newBlock, mode, tr) + writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "," + str(bill.diff/oldDiff) + "\n") + parent = newName + self.assertTrue(bill.diff < oldDiff) + oldDiff = bill.diff + + # Now we go back to the target rate. We have 170 slow blocks in the queue and 50 in the sample size. Difficulty will continue to drop for another 120 blocks... + print("Now we go back to the target rate. We have 170 slow blocks in the queue and 50 in the sample size. Difficulty will continue to drop for another 120 blocks...") + a = 1.0 + b = 1.0/a + + while len(bill.blocks)<1490: + newName = newIdent(len(bill.blocks)) + t += deltaT*a + s += deltaT*a + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + + bill.addBlock(newBlock, mode, tr) + writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "," + str(bill.diff/oldDiff) + "\n") + parent = newName + self.assertTrue(bill.diff < oldDiff) + oldRatio = bill.diff/oldDiff + oldDiff = bill.diff + #print(str(result) + ", " + str(bill.diff) + ", " + str(oldDiff)) + + # Now all 170 slow blocks are not only in the queue but in our sample. The *multiplicative factor* between timesteps should be identical for the next 790 blocks.. leading to AN EXPONENTIAL DECAY OF DIFFICULTY. + print("Now all 170 slow blocks are not only in the queue but in our sample. The *multiplicative factor* between timesteps should be identical for the next 790 blocks.. leading to AN EXPONENTIAL DECAY OF DIFFICULTY.") + a = 1.0 + b = 1.0/a + while len(bill.blocks)<2279: + newName = newIdent(len(bill.blocks)) + t += deltaT + s += deltaT + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + + bill.addBlock(newBlock, mode, tr) + writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "," + str(bill.diff/oldDiff) + "\n") + ratio = bill.diff/oldDiff + parent = newName + err = ratio - oldRatio + #print("Difference between last ratio and next ratio:" + str(err)) + self.assertTrue(err*err < 10**-15) + oldDiff = bill.diff + oldRatio = ratio + + print("Now adding a single new block will cause our 170 slow blocks to start dropping out of our sample, so the ratio should start returning to 1.0.") + oldAwayFromOne = abs(oldRatio - 1.0) # Ratio should be returning to 1.0 so this difference should go to zero + oldAwayFromOne = oldAwayFromOne*oldAwayFromOne + + # For the next 170 blocks as our perturbed blocks drop out of our sample, our + # estimated block arrival rate will return to "normal" so the multiplicative + # difference in difficulty should return to 1.0. + print("For the next 170 blocks as our perturbed blocks drop out of our sample, ourestimated block arrival rate will return to normal so the multiplicative difference in difficulty should return to 1.0.") + a = 1.0 + b = 1.0/a + while len(bill.blocks)<2449: + newName = newIdent(len(bill.blocks)) + t += deltaT*a + s += deltaT*a + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + + bill.addBlock(newBlock, mode, tr) + writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "," + str(bill.diff/oldDiff) + "\n") + ratio = bill.diff/oldDiff + #print("New ratio = " + str(ratio) + " and oldRatio = " + str(oldRatio)) + self.assertTrue(ratio > oldRatio) + awayFromOne = abs(ratio - 1.0) # Ratio should be returning to 1.0 so this difference should go to zero + awayFromOne = awayFromOne*awayFromOne + self.assertTrue(awayFromOne < oldAwayFromOne) # This return will be monotonic in our manufactured example. + parent = newName + oldDiff = bill.diff + oldRatio = ratio + oldAwayFromOne = awayFromOne + + + # Now difficulty should remain frozen for as long as we like. + + a = 1.0 + b = 1.0/a + while len(bill.blocks)<2500: + newName = newIdent(len(bill.blocks)) + t += deltaT*a + s += deltaT*a + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + + bill.addBlock(newBlock, mode, tr) + writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "," + str(bill.diff/oldDiff) + "\n") + parent = newName + self.assertEqual(bill.diff, oldDiff) + oldDiff = bill.diff + + + + + def test_nak(self): + # Since Nakamoto difficulty is derived from the MLE of the block arrival rate, + # we already know how it "should" behave in a poisson process, etc. + # TODO: Generate N samples of MLEs of Poisson rates compared to known homog. + # poisson rate, show that the resulting code does not result in unusual measurements + # more often than expected. + mode = "Nakamoto" + tr = 1.0/600000.0 + deltaT = 600000.0 + bill = Blockchain([], verbosity=True) + bill.targetRate = tr + # Bitcoin updating at 1 block per 10 minutes + + name = newIdent(0) + t = 0.0 + s = 0.0 + diff = 1.0 + params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} + genesis = Block(params) + + self.assertEqual(genesis.ident,name) + self.assertEqual(genesis.discoTimestamp,t) + self.assertEqual(genesis.arrivTimestamp,s) + self.assertTrue(genesis.parent is None) + self.assertEqual(genesis.diff,diff) + + bill.addBlock(genesis, mode, tr) + + self.assertTrue(genesis.ident in bill.blocks) + self.assertTrue(genesis.ident in bill.leaves) + self.assertEqual(len(bill.miningIdents),1) + self.assertEqual(genesis.ident, bill.miningIdents[0]) + self.assertEqual(bill.diff, 1.0) + + parent = genesis.ident + oldDiff = bill.diff + i = 1 + + while len(bill.blocks)<2016*i-1: + newName = newIdent(len(bill.blocks)) + t += deltaT + s += deltaT + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + bill.addBlock(newBlock, mode, tr) + parent = newName + + # Just one more block and difficulty should recompute. + print("Just one more block and difficulty should recompute.") + self.assertEqual(bill.diff, oldDiff) + newName = newIdent(len(bill.blocks)) + t += deltaT + s += deltaT + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + bill.addBlock(newBlock, mode, tr) + parent = newName + self.assertEqual(bill.diff, oldDiff) + + oldDiff = bill.diff + i += 1 + + while len(bill.blocks)<2016*i-1: + newName = newIdent(len(bill.blocks)) + t += deltaT + s += deltaT + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + + bill.addBlock(newBlock, mode, tr) + parent = newName + + # Just one more block and difficulty should recompute. + print("Just one more block and difficulty should again recompute.") + self.assertEqual(bill.diff, oldDiff) + newName = newIdent(len(bill.blocks)) + t += deltaT + s += deltaT + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + bill.addBlock(newBlock, mode, tr) + parent = newName + self.assertEqual(bill.diff, oldDiff) + + oldDiff = bill.diff + i += 1 + a = 1.1 + b = 1.0/a + + # If blocks arrive slightly further apart, difficulty should drop. + while len(bill.blocks)<2016*i-1: + newName = newIdent(len(bill.blocks)) + t += deltaT*a + s += deltaT*a + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + + bill.addBlock(newBlock, mode, tr) + parent = newName + + print("Just one more block and difficulty will go down.") + + self.assertEqual(bill.diff, oldDiff) + newName = newIdent(len(bill.blocks)) + t += deltaT*a + s += deltaT*a + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + bill.addBlock(newBlock, mode, tr) + parent = newName + err = abs(bill.diff - oldDiff*b) + self.assertTrue(err*err < 10**-15) + oldDiff = bill.diff + i += 1 + + + # If blocks then arrive on target, difficulty should freeze. + a = 1.0 + b = 1.0/a + while len(bill.blocks)<2016*i-1: + newName = newIdent(len(bill.blocks)) + t += deltaT*a + s += deltaT*a + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + + bill.addBlock(newBlock, mode, tr) + parent = newName + + self.assertEqual(bill.diff, oldDiff) + newName = newIdent(len(bill.blocks)) + t += deltaT*a + s += deltaT*a + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + bill.addBlock(newBlock, mode, tr) + parent = newName + self.assertEqual(bill.diff, oldDiff) + oldDiff = bill.diff + i += 1 + + # If blocks arrive too close together, difficulty should increase. + a = 0.9 + b = 1.0/a + while len(bill.blocks)<2016*i-1: + newName = newIdent(len(bill.blocks)) + t += deltaT*a + s += deltaT*a + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + + bill.addBlock(newBlock, mode, tr) + parent = newName + + print("Just one more block and difficulty should go up.") + self.assertEqual(bill.diff, oldDiff) + newName = newIdent(len(bill.blocks)) + t += deltaT*a + s += deltaT*a + diff = bill.diff + params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} + newBlock = Block(params) + bill.addBlock(newBlock, mode, tr) + parent = newName + err = abs(bill.diff - oldDiff*b) + self.assertTrue(err*err < 10**-15) + + -suite = unittest.TestLoader().loadTestsFromTestCase(Test_Blockchain) -unittest.TextTestRunner(verbosity=1).run(suite) +#suite = unittest.TestLoader().loadTestsFromTestCase(Test_Blockchain) +#unittest.TextTestRunner(verbosity=1).run(suite) diff --git a/source-code/Poisson-Graphs/Edge.py b/source-code/Poisson-Graphs/Edge.py index 37574c2..b3634f2 100644 --- a/source-code/Poisson-Graphs/Edge.py +++ b/source-code/Poisson-Graphs/Edge.py @@ -4,7 +4,7 @@ class Edge(object): ''' Edge object. Has an identity, some data, and a dict of nodes. ''' - def __init__(self, params=["", {}, True]): + def __init__(self, params): try: assert len(params)==3 except AssertionError: @@ -29,66 +29,11 @@ class Edge(object): class Test_Edge(unittest.TestCase): def test_e(self): - nellyIdent = newIdent(0) - bill = Blockchain([], verbosity=True) - - name = newIdent(0) - t = time.time() - 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}) + nelly = Node(params) + milly = Node(params) + ed = Edge(params) + ed.nodes.update({nelly.ident:nelly, milly.ident:milly}) + self.assertEqual(len(self.nodes),2) suite = unittest.TestLoader().loadTestsFromTestCase(Test_Edge) diff --git a/source-code/Poisson-Graphs/FishGraph.py b/source-code/Poisson-Graphs/FishGraph.py deleted file mode 100644 index b1168d5..0000000 --- a/source-code/Poisson-Graphs/FishGraph.py +++ /dev/null @@ -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) - - diff --git a/source-code/Poisson-Graphs/Graph.py b/source-code/Poisson-Graphs/Graph.py index ade6267..54e5645 100644 --- a/source-code/Poisson-Graphs/Graph.py +++ b/source-code/Poisson-Graphs/Graph.py @@ -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): ''' - Graph object. Contains some data, a dict of nodes, and a dict of edges. + Explanation ''' - def __init__(self, params={}, verbosity=True): - self.data=params - self.verbose = verbosity + 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.data = params[9] - def createGraph(self, numNodes, probEdge, maxNeighbors): - # Create a new random graph with numNodes nodes, a - # likelihood any unordered pair of vertices has an edge - # probEdge, and maximum number of neighbors per node - # maxNeighbors. + self.blankBlockchain = Blockchain() + self.blankBlockchain.targetRate = self.data["targetRate"] + self.blankBlockchain.mode = self.data["mode"] - # First, include inputted information into self.data - self.data.update({"probEdge":probEdge, "maxNeighbors":maxNeighbors}) + self._createInit() - # 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 _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) - 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) + 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") + + + + + + + diff --git a/source-code/Poisson-Graphs/Node.py b/source-code/Poisson-Graphs/Node.py index 25447b2..be9e9d9 100644 --- a/source-code/Poisson-Graphs/Node.py +++ b/source-code/Poisson-Graphs/Node.py @@ -1,941 +1,123 @@ from Blockchain import * -import copy +from copy import * class Node(object): ''' Node object. params [identity, blockchain (data), verbosity, difficulty] ''' def __init__(self, params={}): + self.ident = None + self.data = {} + self.verbose = None + self.edges = {} + self.mode = None + self.targetRate = None try: - assert len(params)==4 + assert len(params)==5 except AssertionError: print("Error, Tried to create malformed node.") else: self.ident = params["ident"] self.data = params["data"] - self.diff = params["diff"] self.verbose = params["verbose"] self.edges = {} + self.mode = params["mode"] + self.targetRate = params["targetRate"] + + def generateBlock(self, discoTime): + newName = newIdent(len(self.data["blockchain"].blocks)) + 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, diffUpdateRate=1, mode="Nakamoto", targetRate=1.0/1209600.0): + 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. - if self.verbose: - print("\t\t Updating blockchain.") - - if self.verbose: - print("\t\tAdding incoming blocks in order of parentage") - - if self.verbose: - print("\t\tFirst step. incBlocks has " + str(len(incBlocks)) + " entries.") - tempData = copy.deepcopy(incBlocks) - - if self.verbose: - print("\t\t Now tempData has " + str(len(tempData)) + " entries.") - + tempData = 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.data["blockchain"].whichLeaf() - #if len(self.data["blockchain"]) % diffUpdateRate == 0: - # self.updateDifficulty(mode, targetRate) + self.data["blockchain"].addBlock(incBlocks[key], self.mode, self.targetRate) del tempData[key] - incBlocks = copy.deepcopy(tempData) - - if self.verbose: - print("\t\t Now incBlocks has " + str(len(incBlocks)) + " entries.") - - if self.verbose: - print("\t\tRemaining steps (while loop)") - + incBlocks = deepcopy(tempData) while len(incBlocks)>0: - if self.verbose: - print("\t\t Now tempData has " + str(len(tempData.blocks)) + " entries.") 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.data["blockchain"].whichLeaf() - del tempData[key] - incBlocks = copy.deepcopy(tempData) - if self.verbose: - print("\t\t Now incBlocks has " + str(len(incBlocks)) + " entries.") - + self.data["blockchain"].addBlock(incBlocks[key], self.mode, self.targetRate) + del tempData[key] + incBlocks = deepcopy(tempData) - def updateDifficulty(self, mode="Nakamoto", targetRate=1.0/1209600.0): - # Compute the difficulty of the next block - # Note for default, targetRate = two weeks/period, seven days/week, 24 hours/day, 60 minutes/hour, 60 seconds/minute) = 1209600 seconds/period - if mode=="Nakamoto": - # Use MLE estimate of poisson process, compare to targetRate, update by multiplying by resulting ratio. - if self.verbose: - print("Beginning update of difficulty with Nakamoto method") - count = 2016 - bc = self.data["blockchain"] - if self.verbose: - print("Checking that blockchain is 2016*n blocks long and some mining identity has been set") - if len(bc.blocks) % 2016 == 0 and len(bc.miningIdents) > 0: - - ident = random.choice(bc.miningIdents) - topTime = copy.deepcopy(bc.blocks[ident].discoTimestamp) - parent = bc.blocks[ident].parent - count = count - 1 - touched = False - while count > 0 and parent is not None: - ident = copy.deepcopy(parent) - parent = bc.blocks[ident].parent - count = count - 1 - touched = True - if not touched: - mleDiscoRate = targetRate - else: - botTime = copy.deepcopy(bc.blocks[ident].discoTimestamp) - - # Algebra is okay: - assert topTime != botTime - - # MLE estimate of arrivals per second: - mleDiscoRate = float(2015)/float(topTime - botTime) - - # Rates can't be negative, but this estimate could be (although it's highly unlikely given Bitcoin's standard choices - # of difficulty update rate, etc. - mleDiscoRate = abs(mleDiscoRate) - - if self.verbose: - print("MLE disco rate = " + str(mleDiscoRate) + " and targetRate = " + str(targetRate)) - # Rate must be positive... so the MLE for block arrival rate - # assuming a Poisson process _is not even well-defined_ as - # an estimate for block arrival rate assuming timestamps are - # inaccurately reported! - - # We use it nonetheless. - - if self.verbose: - print("MLE discovery rate = " + str(mleDiscoRate)) - print("Difficulty before adjustment = " + str(self.diff)) - - # Update difficulty multiplicatively - self.diff = self.diff*mleDiscoRate/targetRate - - if self.verbose: - print("Difficulty after adjustment = ", str(self.diff)) - - elif mode=="vanSaberhagen": - # Similar to above, except use 1200 blocks, discard top 120 and bottom 120 after sorting. - # 4 minute blocks in the original cryptonote, I believe... targetRate = 1.0/ - # 4 minutes/period, 60 seconds/minute ~ 240 seconds/period - # assert targetRate==1.0/240.0 - count = 1200 - bc = self.data["blockchain"] - bc.whichLeaf() - assert self.diff != 0.0 - if len(bc.blocks) > 120: - assert type(bc.miningIdents)==type([]) - assert len(bc.miningIdents) > 0 - ident = random.choice(bc.miningIdents) - bl = [] - bl.append(copy.deepcopy(bc.blocks[ident].discoTimestamp)) - parent = bc.blocks[ident].parent - count = count - 1 - while count > 0 and parent is not None: - ident = copy.deepcopy(parent) - bl.append(copy.deepcopy(bc.blocks[ident].discoTimestamp)) - parent = bc.blocks[ident].parent - count = count-1 - # sort - bl = sorted(bl) - assert len(bl)<=1200 - - #print("Sample size = " + str(len(bl))) - # remove 10 and 90 %-iles - numOutliers = round(len(bl)/5)//2 - assert numOutliers <= 120 - #print("Number of outliers = " + str(numOutliers)) - if numOutliers > 0: - bl = bl[numOutliers:-numOutliers] - #print("New Sample Size = " + str(len(bl))) - - - # get topTime and botTime - if self.verbose: - print("bl[0] = " + str(bl[0]) + ",\tbl[-1] = " + str(bl[-1])) - topTime = bl[-1] - botTime = bl[0] - if self.verbose: - print("list of timestamps = " + str(bl)) - print("topTime = " + str(bl[-1])) - print("botTime = " + str(bl[0])) - - # Assert algebra will work - # 1200 - 2*120 = 1200 - 240 = 960 - assert 0 < len(bl) and len(bl) < 961 - assert topTime - botTime >= 0.0 - - # Sort of the MLE: # blocks/difference in reported times - # But not the MLE, since the reported times may not be - # the actual times, the "difference in reported times" != - # "ground truth difference in block discoery times" in general - naiveDiscoRate = (960 - count)/(topTime - botTime) - - # How much should difficulty change? - self.diff = self.diff*(naiveDiscoRate/targetRate) - - elif mode=="MOM:expModGauss": - # Similar to "vanSaberhagen" except with 2-minute blocks and - # we attempt to take into account that "difference in timestamps" - # can be negative by: - # 1) insisting that the ordering induced by the blockchain and - # 2) modeling timestamps as exponentially modified gaussian. - # If timestamps are T = X + Z where X is exponentially dist- - # ributed with parameter lambda and Z is some Gaussian - # noise with average mu and variance sigma2, then we can est- - # imate sigma2, mu, and lambda: - # mu ~ mean - stdev*(skewness/2)**(1.0/3.0) - # sigma2 ~ variance*(1-(skewness/2)**(2.0/3.0)) - # lambda ~ (1.0/(stdev))*(2/skewness)**(1.0/3.0) - assert targetRate==1.0/120.0 - count = 1200 - bc = self.data["blockchain"] - if len(bc.miningIdents) > 0: - ident = random.choice(bc.miningIdents) - - bl = [] - bl.append(copy.deepcopy(bc.blocks[ident].discoTimestamp)) - parent = bc.blocks[ident].parent - count = count - 1 - while count > 0 and parent is not None: - ident = copy.deepcopy(parent) - bl.append(copy.deepcopy(bc.blocks[ident].discoTimestamp)) - parent = bc.blocks[ident].parent - count = count-1 - if len(bl) > 120: - sk = skew(bl) - va = var(bl) - stdv = sqrt(va) - lam = (1.0/stdv)*(2.0/sk)**(1.0/3.0) - else: - lam = targetRate # we will not change difficulty unless we have at least 120 blocks of data (arbitrarily selected) - self.diff = self.diff*(lam/targetRate) - else: - print("Error, invalid difficulty mode entered.") - - def propagate(self, t, blockIdent): + def propagate(self, timeOfProp, blockIdent): for edgeIdent in self.edges: - e = self.edges[edgeIdent] - l = e.data["length"] - toa = t + l - mIdent = e.getNeighbor(self.ident) - m = e.nodes[mIdent] - bc = m.data["blockchain"] + 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"] - pendingDat = {"timeOfArrival":toa, "destIdent":mIdent, "block":mybc.blocks[blockIdent]} + 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_nakamoto(self): - print("Beginning test of Nakamoto difficulty adjustment") - print("Setting initial values") - target = 100.0 # rate = blocks/s - verbose = False - deltaT = 1.0/target # forced wait time - arrivalList = [] + def test_all(self): + bill = Blockchain([], verbosity=True) mode="Nakamoto" + tr = 1.0/600000.0 + deltaT = 600000.0 + bill.targetRate = tr - print("Generating node") - nellyIdent = newIdent(0) - offset = random.random() - intensity = random.random() - - print("Generating initial blockchain") - # Create a new initial blockchain object - bill = Blockchain([], verbosity=verbose) name = newIdent(0) - t = time.time() - t += offset - arrivalList.append(t) - s = t+random.random() - diff = 1.0 - oldDiff = copy.deepcopy(diff) - params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} - genesis = Block(params) - print("Adding block") - bill.addBlock(genesis) - bill.whichLeaf() - - # Check that it consists only of the genesis block - self.assertTrue(len(bill.blocks)==1) - self.assertTrue(genesis.ident in bill.blocks) - self.assertTrue(genesis.parent is None) - - print("Finish creating node") - # Create node with this blockchain. - nodeData = {"blockchain":bill, "intensity":intensity, "offset":offset} - params = {"ident":nellyIdent, "data":nodeData, "diff":diff, "verbose":verbose} - nelly = Node(params) - - # Check node creation worked - self.assertEqual(nelly.ident, nellyIdent) - self.assertEqual(nelly.data["blockchain"], bill) - self.assertEqual(nelly.diff, diff) - self.assertEqual(nelly.data["intensity"], intensity) - self.assertEqual(nelly.data["offset"], offset) - - # Sleep and add a block on top of genesis - if verbose: - print("sleeping") - time.sleep(deltaT) - - print("Giving genesis block a child") - name = newIdent(1) - t = time.time() - t += nelly.data["offset"] - arrivalList.append(t) - s = t+random.random() - diff = oldDiff - params = {"ident":name, "disco":t, "arriv":s, "parent":genesis.ident, "diff":diff} - blockA = Block(params) - nelly.updateBlockchain({blockA.ident:blockA}) - oldIdent = blockA.ident - - # Check this worked - self.assertEqual(len(nelly.data["blockchain"].blocks),2) - self.assertTrue(blockA.ident in nelly.data["blockchain"].blocks) - self.assertTrue(genesis.ident in nelly.data["blockchain"].blocks) - self.assertEqual(genesis.ident, nelly.data["blockchain"].blocks[blockA.ident].parent) - - print("Updating difficulty") - # Update the difficulty score - nelly.updateDifficulty(mode, targetRate = target) # With only two blocks, nothing should change. - self.assertEqual(nelly.diff, oldDiff) - - # Print regardless of verbosity: - print("Now generating first difficulty adjustment period.") - - # Now we are going to fast forward to right before the first difficulty adjustment. - N = len(nelly.data["blockchain"].blocks) - while(N < 2015): - if N % 100 == 0: - print("\tN=" + str(N)) - name = newIdent(N) - t = time.time() - t += nelly.data["offset"] - arrivalList.append(t) - s = t+random.random() - diff = nelly.diff - oldDiff = diff - params = {"ident":name, "disco":t, "arriv":s, "parent":oldIdent, "diff":diff} - oldIdent = copy.deepcopy(name) - block = Block(params) - nelly.updateBlockchain({block.ident:block}) - - # Check this worked - self.assertEqual(len(nelly.data["blockchain"].blocks),N+1) - self.assertTrue(block.ident in nelly.data["blockchain"].blocks) - - # Update the difficulty score - nelly.updateDifficulty(mode, targetRate = target) # With N < 2016, nothing should change. - self.assertEqual(nelly.diff, oldDiff) - N = len(nelly.data["blockchain"].blocks) - time.sleep(deltaT) - - name = newIdent(N) - t = time.time() - t += nelly.data["offset"] - arrivalList.append(t) - s = t+random.random() - diff = oldDiff - params = {"ident":name, "disco":t, "arriv":s, "parent":oldIdent, "diff":diff} - block = Block(params) - nelly.updateBlockchain({block.ident:block}) - - # Check this worked - self.assertEqual(len(nelly.data["blockchain"].blocks),N+1) - self.assertTrue(block.ident in nelly.data["blockchain"].blocks) - - # Update the difficulty score - nelly.updateDifficulty(mode, targetRate = target) # With N < 2016, nothing should change. - # Note: 2016 blocks is 2015 block inter-arrival times. - expRatioNumerator = float(2015)/(arrivalList[-1] - arrivalList[-2016]) - expRatio = expRatioNumerator/target - expDiff = oldDiff*expRatio - self.assertEqual(nelly.diff, expDiff) - - # The following should fail, because our sample size is incorrect. - expRatioNumerator = float(2016)/(arrivalList[-1] - arrivalList[-2016]) - expRatio = expRatioNumerator/target - expDiff = oldDiff*expRatio - self.assertFalse(nelly.diff - expDiff == 0.0) - - - # Print regardless of verbosity: - print("Now generating second difficulty adjustment period.") - - # Now we are going to fast forward to right before the next difficulty adjustment. - # This time, though, we are going to re-set the block inter-arrival time deltaT - # to half. This should drive difficulty up. - lastDifficultyScore = copy.deepcopy(nelly.diff) - N = len(nelly.data["blockchain"].blocks) - while(N < 4031): - if N % 100 == 0: - print("\tN=" + str(N)) - name = newIdent(N) - t = time.time() - t += nelly.data["offset"] - arrivalList.append(t) - s = t+random.random() - diff = nelly.diff - oldDiff = diff - params = {"ident":name, "disco":t, "arriv":s, "parent":oldIdent, "diff":diff} - oldIdent = copy.deepcopy(name) - block = Block(params) - nelly.updateBlockchain({block.ident:block}) - - # Check this worked - self.assertEqual(len(nelly.data["blockchain"].blocks),N+1) - self.assertTrue(block.ident in nelly.data["blockchain"].blocks) - - # Update the difficulty score - nelly.updateDifficulty(mode, targetRate = target) # With N < 2016, nothing should change. - self.assertEqual(nelly.diff, oldDiff) - N = len(nelly.data["blockchain"].blocks) - time.sleep(0.01*deltaT) - - # Now if we add a single new block, we should trigger difficulty adjustment. - name = newIdent(N) - t = time.time() - t += nelly.data["offset"] - arrivalList.append(t) - s = t+random.random() - diff = oldDiff - params = {"ident":name, "disco":t, "arriv":s, "parent":oldIdent, "diff":diff} - block = Block(params) - nelly.updateBlockchain({block.ident:block}) - - # Check this worked - self.assertEqual(len(nelly.data["blockchain"].blocks),N+1) - self.assertTrue(block.ident in nelly.data["blockchain"].blocks) - - # Update the difficulty score. - nelly.updateDifficulty(mode, targetRate = target) - expRatioNumerator = float(2015)/(arrivalList[-1] - arrivalList[-2016]) - expRatio = expRatioNumerator/target - expDiff = oldDiff*expRatio - print("expRatio = " + str(expRatio) + ", lastDifficultyScore = " + str(lastDifficultyScore) + ", new difficulty = " + str(nelly.diff)) - self.assertEqual(nelly.diff, expDiff) - ''' - - - - - def test_vs(self): - print("Beginning test of vanSaberhagen difficulty adjustment.") - print("Setting initial values") - target = 10.0 # 1.0/240.0 # rate = blocks/s - verbose = False - deltaT = 1.0/target # forced wait time - arrivalList = [] - mode="vanSaberhagen" - - print("Instantiating new node") - nellyIdent = newIdent(0) - offset = random.random() - intensity = random.random() - - print("Creating new blockchain for new node") - # Create a new initial blockchain object - bill = Blockchain([], verbosity=verbose) - name = newIdent(0) - t = time.time() - t += offset - arrivalList.append(t) - s = t+random.random() + t = 0.0 + s = t diff = 1.0 params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} genesis = Block(params) - print("Adding genesis block") - bill.addBlock(genesis) - bill.whichLeaf() + bill.addBlock(genesis, mode, tr) - # Check that it consists only of the genesis block - self.assertTrue(len(bill.blocks)==1) - self.assertTrue(genesis.ident in bill.blocks) - self.assertTrue(genesis.parent is None) - self.assertTrue(genesis.ident in bill.leaves) + parent = genesis.ident - print("Making node") - # Create node with this blockchain. - nodeData = {"blockchain":bill, "intensity":intensity, "offset":offset} - params = {"ident":nellyIdent, "data":nodeData, "diff":diff, "verbose":verbose} + 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) - # Check node creation worked - self.assertEqual(nelly.ident, nellyIdent) - self.assertEqual(nelly.data["blockchain"], bill) - self.assertEqual(nelly.diff, diff) - self.assertEqual(nelly.data["intensity"], intensity) - self.assertEqual(nelly.data["offset"], offset) - - # Sleep and add a block on top of genesis - if verbose: - print("sleeping") - time.sleep(deltaT) - - print("Give genesis a child") - name = newIdent(1) - t = time.time() - t += nelly.data["offset"] - arrivalList.append(t) - s = t+random.random() - oldDiff = copy.deepcopy(diff) - diff = copy.deepcopy(nelly.diff) - assert diff != 0.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":genesis.ident, "diff":diff} - blockA = Block(params) - nelly.updateBlockchain({blockA.ident:blockA}) - oldIdent = blockA.ident - - # Check this worked - self.assertEqual(len(nelly.data["blockchain"].blocks),2) - self.assertTrue(blockA.ident in nelly.data["blockchain"].blocks) - self.assertTrue(genesis.ident in nelly.data["blockchain"].blocks) - self.assertEqual(genesis.ident, nelly.data["blockchain"].blocks[blockA.ident].parent) - - # Update the difficulty score - nelly.updateDifficulty(mode, targetRate = target) # With only two blocks, nothing should change. - assert nelly.diff != 0.0 - self.assertEqual(nelly.diff, oldDiff) - self.assertFalse(nelly.diff == -0.0) - - # Print regardless of verbosity: - print("Now generating fulls sample size.") - - # Now we are going to fast forward to a "full sample size" period of time. - N = len(nelly.data["blockchain"].blocks) - while(N < 1200): - name = newIdent(N) - if N % 100 == 0: - print("\tNow adding block N=" + str(N)) - t = time.time() - t += nelly.data["offset"] - arrivalList.append(t) - s = t+random.random() - oldDiff = copy.deepcopy(diff) - diff = copy.deepcopy(nelly.diff) - assert diff != 0.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":oldIdent, "diff":diff} - oldIdent = copy.deepcopy(name) - block = Block(params) - nelly.updateBlockchain({block.ident:block}) - - # Check this worked - self.assertEqual(len(nelly.data["blockchain"].blocks),N+1) - self.assertTrue(block.ident in nelly.data["blockchain"].blocks) - - # Update the difficulty score - nelly.updateDifficulty(mode, targetRate = target) # With N < 100, nothing should change. - if N < 100: - self.assertEqual(nelly.diff, oldDiff) - N = len(nelly.data["blockchain"].blocks) - time.sleep(0.5*deltaT) - - print("Adding one more block") - name = newIdent(N) - t = time.time() - t += nelly.data["offset"] - arrivalList.append(t) - s = t+random.random() - oldDiff = diff - diff = nelly.diff - assert diff != 0.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":oldIdent, "diff":nelly.diff} - block = Block(params) - nelly.updateBlockchain({block.ident:block}) - - # Check this worked - self.assertEqual(len(nelly.data["blockchain"].blocks),N+1) - self.assertTrue(block.ident in nelly.data["blockchain"].blocks) - - # Update the difficulty score - nelly.updateDifficulty(mode, targetRate = target) # With N < 2016, nothing should change. - # Note: 2016 blocks is 2015 block inter-arrival times. - print(str(arrivalList[-120]) + ", " + str(arrivalList[-1080]) + ", " + str(arrivalList[-120]-arrivalList[-1080]) + ", " + str(float(959)/(arrivalList[-120]-arrivalList[-1080]))+ ", " + str(float(float(959)/(arrivalList[-120]-arrivalList[-1080]))/float(target))) - expRatioNumerator = float(959)/(arrivalList[-120] - arrivalList[-1080]) - expRatio = expRatioNumerator/target - print(expRatio) - expDiff = oldDiff*expRatio - print(expDiff) - print("expDiff = " + str(expDiff) + " and nelly.diff = " + str(nelly.diff)) - self.assertEqual(nelly.diff, expDiff) - - - # Print regardless of verbosity: - print("Now fast forwarding past the tail end of the last period..") - # Now we are going to fast forward to right before the next difficulty adjustment. - # This time, though, we are going to re-set the block inter-arrival time deltaT - # to half. This should drive difficulty up. - lastDifficultyScore = copy.deepcopy(nelly.diff) - N = len(nelly.data["blockchain"].blocks) - while(N < 1700): - name = newIdent(N) - t = time.time() - t += nelly.data["offset"] - arrivalList.append(t) - s = t+random.random() - diff = nelly.diff - oldDiff = diff - params = {"ident":name, "disco":t, "arriv":s, "parent":oldIdent, "diff":diff} - oldIdent = copy.deepcopy(name) - block = Block(params) - nelly.updateBlockchain({block.ident:block}) - - # Check this worked - self.assertEqual(len(nelly.data["blockchain"].blocks),N+1) - self.assertTrue(block.ident in nelly.data["blockchain"].blocks) - - # Update the difficulty score - nelly.updateDifficulty(mode, targetRate = target) # With N < 2016, nothing should change. - self.assertEqual(nelly.diff, oldDiff) - N = len(nelly.data["blockchain"].blocks) - time.sleep(0.01*deltaT) - - # Now if we add a single new block, we should trigger difficulty adjustment. - name = newIdent(N) - t = time.time() - t += nelly.data["offset"] - arrivalList.append(t) - s = t+random.random() - diff = oldDiff - params = {"ident":name, "disco":t, "arriv":s, "parent":oldIdent, "diff":diff} - block = Block(params) - nelly.updateBlockchain({block.ident:block}) - - # Check this worked - self.assertEqual(len(nelly.data["blockchain"].blocks),N+1) - self.assertTrue(block.ident in nelly.data["blockchain"].blocks) - - # Update the difficulty score. - nelly.updateDifficulty(mode, targetRate = target) - expRatioNumerator = float(959)/(arrivalList[-120] - arrivalList[-1080]) - expRatio = expRatioNumerator/target - expDiff = oldDiff*expRatio - print("expRatio = " + str(expRatio) + ", lastDifficultyScore = " + str(lastDifficultyScore) + ", new difficulty = " + str(nelly.diff)) - self.assertEqual(nelly.diff, expDiff) - - - - def test_modexp(self): - pass - - '''# Check this worked - if mode == "Nakamoto": - # In this case we take simple MLE estimate - ratio = 1.0/abs(t1-t) - print("Nakamoto mle = " + str(ratio)) - ratio = ratio/target - print("Normalized = " + str(ratio)) - print("New diff = " + str(ratio*oldDiff)) - self.assertEqual(nelly.diff, ratio*oldDiff) - elif mode == "vanSaberhagen": - # In this case, with only 2 blocks, we just use simple MLE again - ratio = 1.0/abs(t1-t) - ratio = ratio/target - self.assertEqual(nelly.diff, ratio*oldDiff) - elif mode == "MOM:expModGauss": - self.assertEqual(nelly.diff, 1.0) - # With at least 120 blocks of data... - #sk = skew(bl) - #va = var(bl) - #stdv = sqrt(va) - #lam = (1.0/stdv)*(2.0/sk)**(1.0/3.0) - #self.diff = self.diff*(lam/targetRate) - # Otherwise, set to 1.0 - else: - print("what world are you living in?") - - if verbose: - print("sleeping 1 seconds") - time.sleep(deltaT/5.0) - - listOfTimes = [copy.deepcopy(t), copy.deepcopy(t1)] - listOfBlocks = [] - - N = len(nelly.data["blockchain"].blocks) - lastIdent = blockA.ident - - bail = False - while N < 10 and not bail: - # Generate new block - name = newIdent(N) - t = time.time() - t += nelly.data["offset"] - s = t+random.random() - oldDiff = copy.deepcopy(nelly.diff) - print("Current difficulty = ", oldDiff) - params = {"ident":name, "disco":t, "arriv":s, "parent":lastIdent, "diff":oldDiff} + while len(nelly.data["blockchain"].blocks) < 2015: + name = newIdent(len(nelly.data["blockchain"].blocks)) + 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) - - # Append new block to running list along with creation time - listOfBlocks.append(newBlock) - listOfTimes.append(copy.deepcopy(t)) - - # Update nelly's blockchain with newBlock nelly.updateBlockchain({newBlock.ident:newBlock}) - lastIdent = name + parent = name - # Quick check that this worked: - self.assertTrue(name in nelly.data["blockchain"].blocks) - self.assertEqual(len(nelly.data["blockchain"].blocks), N+1) - N = len(nelly.data["blockchain"].blocks) - - # Update difficulty - nelly.updateDifficulty(mode, targetRate = 100.0) - # Quick check that this worked: - if mode == "Nakamoto": - # In this case we take use top block and genesis block - ratio = float(len(nelly.data["blockchain"].blocks) - 1)/(listOfTimes[-1] - listOfTimes[0]) - ratio = ratio / target - self.assertEqual(nelly.diff, ratio*oldDiff) - print("Hoped for difficulty = " + str(oldDiff*ratio) + ", and computed = " + str(nelly.diff)) - elif mode == "vanSaberhagen": - # This case coincides with nakamoto until block 10 - ratio = float( len(nelly.data["blockchain"].blocks) - 1)/(listOfTimes[-1] - listOfTimes[0]) - ratio = ratio / target - self.assertEqual(nelly.diff, ratio*oldDiff) - elif mode == "MOM:expModGauss": - self.assertEqual(nelly.diff, 1.0) - # With at least 120 blocks of data... - #sk = skew(bl) - #va = var(bl) - #stdv = sqrt(va) - #lam = (1.0/stdv)*(2.0/sk)**(1.0/3.0) - #self.diff = self.diff*(lam/targetRate) - # Otherwise, set to 1.0 - else: - print("what world are you living in?") - - # Sleep a random time - print("Sleeping a random sub-second, working on block " + str(N)) - deltaT = deltaT*ratio - time.sleep(deltaT/5.0) - - while N < 120 and not bail: - # Generate new block - name = newIdent(N) - t = time.time() - t += nelly.data["offset"] - s = t+random.random() - oldDiff = copy.deepcopy(nelly.diff) - params = {"ident":name, "disco":t, "arriv":s, "parent":lastIdent, "diff":oldDiff} + while len(nelly.data["blockchain"].blocks) < 5000: + name = newIdent(len(nelly.data["blockchain"].blocks)) + diff = nelly.data["blockchain"].diff + t += deltaT*diff + s = t + params = {"ident":name, "disco":t, "arriv":s, "parent":parent, "diff":diff} newBlock = Block(params) - - # Append new block to running list along with creation time - listOfBlocks.append(newBlock) - listOfTimes.append(copy.deepcopy(t)) - - # Update nelly's blockchain with newBlock nelly.updateBlockchain({newBlock.ident:newBlock}) - lastIdent = name - - # Quick check that this worked: - self.assertTrue(name in nelly.data["blockchain"].blocks) - self.assertEqual(len(nelly.data["blockchain"].blocks), N+1) - N = len(nelly.data["blockchain"].blocks) + parent = name - # Update difficulty - nelly.updateDifficulty(mode, targetRate = 100.0) - - # Quick check that this worked: - if mode == "Nakamoto": - # In this case we take use top block and genesis block - ratio = float(len(nelly.data["blockchain"].blocks)-1)/(listOfTimes[-1] - listOfTimes[0]) - ratio = ratio / target - self.assertEqual(nelly.diff, oldDiff*ratio) - print("Hoped for difficulty = " + str(oldDiff*ratio) + ", and computed = " + str(nelly.diff)) - elif mode == "vanSaberhagen": - # This case no longer coincides with Nakamoto... - numOutliers = len(nelly.data["blockchain"].blocks)//10 - numOutliers = min(numOutliers, 120) - ratio = float(len(nelly.data["blockchain"].blocks) - 2*numOutliers - 1)/(listOfTimes[-numOutliers] - listOfTimes[numOutliers]) - ratio = ratio / target - self.assertEqual(nelly.diff, oldDiff*ratio) - elif mode == "MOM:expModGauss": - # With at least 120 blocks of data... - count = 1200 - bl = [] - bl.append(copy.deepcopy(bc.blocks[lastIdent].discoTimestamp)) - parent = bc.blocks[lastIdent].parent - count = count - 1 - while count > 0 and parent is not None: - ident = copy.deepcopy(parent) - bl.append(copy.deepcopy(bc.blocks[ident].discoTimestamp)) - parent = bc.blocks[ident].parent - count = count-1 - if len(bl) > 120: - sk = skew(bl) - va = var(bl) - stdv = sqrt(va) - lam = (1.0/stdv)*(2.0/sk)**(1.0/3.0) - else: - lam = target - ratio = lam/target - self.assertEqual(nelly.diff, oldDiff*ratio) - - else: - print("what world are you living in?") - - # Sleep a random time - print("Sleeping a random sub-second, working on block " + str(N)) - deltaT = deltaT*ratio - time.sleep(deltaT/5.0) - - while N < 2400 and not bail: - # Generate new block - name = newIdent(N) - t = time.time() - t += nelly.data["offset"] - s = t+random.random() - oldDiff = copy.deepcopy(nelly.diff) - params = {"ident":name, "disco":t, "arriv":s, "parent":lastIdent, "diff":oldDiff} - newBlock = Block(params) - - # Append new block to running list along with creation time - listOfBlocks.append(newBlock) - listOfTimes.append(copy.deepcopy(t)) - - # Update nelly's blockchain with newBlock - nelly.updateBlockchain({newBlock.ident:newBlock}) - lastIdent = name - - # Quick check that this worked: - self.assertTrue(name in nelly.data["blockchain"].blocks) - self.assertEqual(len(nelly.data["blockchain"].blocks), N+1) - N = len(nelly.data["blockchain"].blocks) - - # Update difficulty - nelly.updateDifficulty(mode, targetRate = 100.0) - - # Quick check that this worked: - if mode == "Nakamoto": - # In this case we take use top block and genesis block - ratio = float(len(nelly.data["blockchain"].blocks)-1)/(listOfTimes[-1] - listOfTimes[0]) - ratio = ratio / target - self.assertEqual(nelly.diff, oldDiff*ratio) - print("Hoped for difficulty = " + str(oldDiff*ratio) + ", and computed = " + str(nelly.diff)) - elif mode == "vanSaberhagen": - # This case no longer coincides with Nakamoto... - numOutliers = len(nelly.data["blockchain"].blocks)//10 - numOutliers = min(numOutliers, 120) - ratio = float(len(nelly.data["blockchain"].blocks) - 2*numOutliers - 1)/(listOfTimes[-numOutliers] - listOfTimes[numOutliers]) - ratio = ratio / target - self.assertEqual(nelly.diff, ratio*oldDiff) - elif mode == "MOM:expModGauss": - # With at least 120 blocks of data... - count = 1200 - bl = [] - bl.append(copy.deepcopy(bc.blocks[lastIdent].discoTimestamp)) - parent = bc.blocks[lastIdent].parent - count = count - 1 - while count > 0 and parent is not None: - ident = copy.deepcopy(parent) - bl.append(copy.deepcopy(bc.blocks[ident].discoTimestamp)) - parent = bc.blocks[ident].parent - count = count-1 - if len(bl) > 120: - sk = skew(bl) - va = var(bl) - stdv = sqrt(va) - lam = (1.0/stdv)*(2.0/sk)**(1.0/3.0) - else: - lam = targetRate - ratio = lam/targetRate - self.assertEqual(nelly.diff, ratio*oldDiff) - - else: - print("what world are you living in?") - - # Sleep a random time - print("Sleeping a random sub-second, working on block " + str(N)) - deltaT = deltaT*ratio - time.sleep(deltaT/5.0) - - - while N < 3600 and not bail: - # Generate new block - name = newIdent(N) - t = time.time() - t += nelly.data["offset"] - s = t+random.random() - oldDiff = nelly.diff - params = {"ident":name, "disco":t, "arriv":s, "parent":lastIdent, "diff":oldDiff} - newBlock = Block(params) - - # Append new block to running list along with creation time - listOfBlocks.append(newBlock) - listOfTimes.append(copy.deepcopy(t)) - - # Update nelly's blockchain with newBlock - nelly.updateBlockchain({newBlock.ident:newBlock}) - lastIdent = name - - # Quick check that this worked: - self.assertTrue(name in nelly.data["blockchain"].blocks) - self.assertEqual(len(nelly.data["blockchain"].blocks), N+1) - N = len(nelly.data["blockchain"].blocks) - - # Update difficulty - nelly.updateDifficulty(mode, targetRate = 100.0) - - # Quick check that this worked: - if mode == "Nakamoto": - # In this case we take use top block and genesis block - ratio = float(2400)/(listOfTimes[-1] - listOfTimes[-2400]) - self.assertEqual(nelly.diff, ratio*oldDiff) - elif mode == "vanSaberhagen": - # This case no longer coincides with Nakamoto... - numOutliers = len(nelly.data["blockchain"].blocks)//10 - numOutliers = min(numOutliers, 120) - ratio = float(len(nelly.data["blockchain"].blocks) - 2*numOutliers)/(listOfTimes[-numOutliers] - listOfTimes[numOutliers]) - self.assertEqual(nelly.diff, ratio*oldDiff) - elif mode == "MOM:expModGauss": - # With at least 120 blocks of data... - count = 1200 - bl = [] - bl.append(copy.deepcopy(bc.blocks[lastIdent].discoTimestamp)) - parent = bc.blocks[lastIdent].parent - count = count - 1 - while count > 0 and parent is not None: - ident = copy.deepcopy(parent) - bl.append(copy.deepcopy(bc.blocks[ident].discoTimestamp)) - parent = bc.blocks[ident].parent - count = count-1 - if len(bl) > 120: - sk = skew(bl) - va = var(bl) - stdv = sqrt(va) - lam = (1.0/stdv)*(2.0/sk)**(1.0/3.0) - else: - lam = targetRate - ratio = lam/targetRate - self.assertEqual(nelly.diff, ratio*oldDiff) - - else: - print("what world are you living in?") - - # Sleep a random time - print("Sleeping a random sub-second, working on block " + str(N)) - deltaT = deltaT*ratio - time.sleep(deltaT/5.0)''' - - -suite = unittest.TestLoader().loadTestsFromTestCase(Test_Node) -unittest.TextTestRunner(verbosity=1).run(suite) +#suite = unittest.TestLoader().loadTestsFromTestCase(Test_Node) +#unittest.TextTestRunner(verbosity=1).run(suite) diff --git a/source-code/Poisson-Graphs/StochasticProcess.py b/source-code/Poisson-Graphs/StochasticProcess.py deleted file mode 100644 index e6739de..0000000 --- a/source-code/Poisson-Graphs/StochasticProcess.py +++ /dev/null @@ -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) - - diff --git a/source-code/Poisson-Graphs/new/Block.py b/source-code/Poisson-Graphs/new/Block.py deleted file mode 100644 index dece697..0000000 --- a/source-code/Poisson-Graphs/new/Block.py +++ /dev/null @@ -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) diff --git a/source-code/Poisson-Graphs/new/Block.py~ b/source-code/Poisson-Graphs/new/Block.py~ deleted file mode 100644 index dece697..0000000 --- a/source-code/Poisson-Graphs/new/Block.py~ +++ /dev/null @@ -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) diff --git a/source-code/Poisson-Graphs/new/Blockchain.py b/source-code/Poisson-Graphs/new/Blockchain.py deleted file mode 100644 index 97a3ba2..0000000 --- a/source-code/Poisson-Graphs/new/Blockchain.py +++ /dev/null @@ -1,1142 +0,0 @@ -from Block import * -import math -from scipy.stats import * -from numpy import * -from copy import deepcopy - -class Blockchain(object): - ''' - Not a true blockchain, of course, but tracks block objects (timestamps) as above. - Each node should be responsible for finding the chain with most cumulative work. - Right now we assume Nakamoto consensus (konsensnakamoto). - ''' - def __init__(self, params=[], verbosity=True): - self.blocks = {} - self.leaves = {} - self.miningIdents = None - self.mIdent = None - self.verbose = verbosity - self.diff = None - self.targetRate = None - - def addBlock(self, blockToAdd, mode="Nakamoto", targetRate=1.0/600000.0): - # In our model we assume difficulty scores of blocks are correct (otherwise they would - # be rejected in the real life network, and we aren't trying to model spam attacks). - assert blockToAdd.ident not in self.blocks - if len(self.blocks)==0: - # In this case, blockToAdd is a genesis block, so we set difficulty - self.diff = deepcopy(blockToAdd.diff) - - self.blocks.update({blockToAdd.ident:blockToAdd}) - self.leaves.update({blockToAdd.ident:blockToAdd}) - if blockToAdd.parent in self.leaves: - del self.leaves[blockToAdd.parent] - self.whichLeaf() - return self.computeDifficulty(mode, targetRate) - - def whichLeaf(self): - # Determine which leaf shall be the parent leaf. - # If the chain has forked *ever* this will not be the case. - maxCumDiff = 0.0 - self.miningIdents = [] - for ident in self.leaves: - tempCumDiff = 0.0 - thisBlockIdent = ident - tempCumDiff += self.blocks[thisBlockIdent].diff - while self.blocks[thisBlockIdent].parent is not None: - thisBlockIdent = self.blocks[thisBlockIdent].parent - tempCumDiff += self.blocks[thisBlockIdent].diff - if tempCumDiff > maxCumDiff: - # If more than one leaf ties for maxCumDiff, each node in the - # network should pick one of these two arbitrarily. Since we - # are storing each blockchain in a hash table (unordered!), for - # each node in the network that observes a tie, each possible leaf - # is equally likely to have been the first one found! So - # we don't need to do anything for the node to select which chain - # to work off of. - self.miningIdents = [ident] - maxCumDiff = tempCumDiff - elif tempCumDiff == maxCumDiff: - self.miningIdents.append(ident) - #print("leaf ident = ", str(ident), ", and tempCumDiff = ", str(tempCumDiff), " and maxCumDiff = ", str(maxCumDiff)) - assert len(self.miningIdents) > 0 - self.mIdent = random.choice(self.miningIdents) - - - # 1 block in 6*10^5 milliseconds=10min - def computeDifficulty(self, mode="Nakamoto", targetRate=1.0/600000.0): - result = None - if mode=="Nakamoto": - # Use MLE estimate of poisson process, compare to targetRate, update by multiplying by resulting ratio. - #if self.verbose: - # print("Beginning update of difficulty with Nakamoto method") - count = 2016 - #if self.verbose: - # print("Checking that blockchain is 2016*n blocks long and some mining identity has been set") - if len(self.blocks) % 2016 == 0 and len(self.miningIdents) > 0: - ident = self.mIdent - topTime = deepcopy(self.blocks[ident].discoTimestamp) - parent = self.blocks[ident].parent - count = count - 1 - touched = False - while count > 0 and parent is not None: - ident = deepcopy(parent) - parent = self.blocks[ident].parent - count = count - 1 - touched = True - if not touched: - mleDiscoRate = targetRate - else: - botTime = deepcopy(self.blocks[ident].discoTimestamp) - - # Algebra is okay: - assert topTime != botTime - - # MLE estimate of arrivals per second: - mleDiscoRate = float(2015)/float(topTime - botTime) - - # Rates can't be negative, but this estimate could be (although it's highly unlikely given Bitcoin's standard choices - # of difficulty update rate, etc. - mleDiscoRate = abs(mleDiscoRate) - - if self.verbose: - print("MLE disco rate = " + str(mleDiscoRate) + " and targetRate = " + str(targetRate)) - # Rate must be positive... so the MLE for block arrival rate - # assuming a Poisson process _is not even well-defined_ as - # an estimate for block arrival rate assuming timestamps are - # inaccurately reported! - - # We use it nonetheless. - - if self.verbose: - print("MLE discovery rate = " + str(mleDiscoRate)) - print("Difficulty before adjustment = " + str(self.diff)) - - # Update difficulty multiplicatively - self.diff = self.diff*mleDiscoRate/targetRate - - if self.verbose: - print("Difficulty after adjustment = ", str(self.diff)) - - elif mode=="vanSaberhagen": - # Similar to above, except use 1200 blocks, discard top 120 and bottom 120 after sorting. - # 4 minute blocks in the original cryptonote, I believe... targetRate = 1.0/ - # 4 minutes/period, 60 seconds/minute ~ 240 seconds/period - # assert targetRate==1.0/240.0 - count = 1200 - #print(self.diff) - assert self.diff != 0.0 - if len(self.blocks) > 120 and len(self.miningIdents) > 0: - ident = self.mIdent - bl = [] - bl.append(deepcopy(self.blocks[ident].discoTimestamp)) - parent = self.blocks[ident].parent - count = count - 1 - while count > 0 and parent is not None: - ident = deepcopy(parent) - bl.append(deepcopy(self.blocks[ident].discoTimestamp)) - parent = self.blocks[ident].parent - count = count-1 - # sort - bl = sorted(bl) - assert len(bl)<=1200 - - #print("Sample size = " + str(len(bl))) - # remove 10 and 90 %-iles - numOutliers = math.ceil(float(len(bl))/float(10)) - assert numOutliers <= 120 - #print("Number of outliers = " + str(numOutliers)) - oldBL = deepcopy(bl) - if numOutliers > 0: - bl = bl[numOutliers:-numOutliers] - #if numOutliers == 120: - # print("\n\nSORTED TS LIST = " + str(oldBL) + "\nModified list = " + str(bl)) - - - # get topTime and botTime - #if self.verbose: - # print("bl[0] = " + str(bl[0]) + ",\tbl[-1] = " + str(bl[-1])) - topTime = bl[-1] - botTime = bl[0] - result = [float(topTime - botTime)] - #print(topTime - botTime) - #if self.verbose: - # print("list of timestamps = " + str(bl)) - # print("topTime = " + str(bl[-1])) - # print("botTime = " + str(bl[0])) - - # Assert algebra will work - # 1200 - 2*120 = 1200 - 240 = 960 - assert 0 < len(bl) and len(bl) < 961 - assert topTime - botTime >= 0.0 - result.append(len(bl)-1) - # Sort of the MLE: # blocks/difference in reported times - # But not the MLE, since the reported times may not be - # the actual times, the "difference in reported times" != - # "ground truth difference in block discoery times" in general - if len(bl)==0: - print("WOOP WOOP NO TIMESTAMPS WTF? We have " + str(len(self.blocks)) + " blocks available, and we are counting " + str(2*numOutliers) + " as outliers. bl = " + str(bl)) - naiveDiscoRate = float(len(bl)-1)/float(topTime - botTime) - - # How much should difficulty change? - assert naiveDiscoRate != 0.0 - assert targetRate != 0.0 - assert self.diff != 0.0 - self.diff = self.diff*naiveDiscoRate/targetRate - - elif mode=="MOM:expModGauss": - # Similar to "vanSaberhagen" except with 2-minute blocks and - # we attempt to take into account that "difference in timestamps" - # can be negative by: - # 1) insisting that the ordering induced by the blockchain and - # 2) modeling timestamps as exponentially modified gaussian. - # If timestamps are T = X + Z where X is exponentially dist- - # ributed with parameter lambda and Z is some Gaussian - # noise with average mu and variance sigma2, then we can est- - # imate sigma2, mu, and lambda: - # mu ~ mean - stdev*(skewness/2)**(1.0/3.0) - # sigma2 ~ variance*(1-(skewness/2)**(2.0/3.0)) - # lambda ~ (1.0/(stdev))*(2/skewness)**(1.0/3.0) - #assert targetRate==1.0/120.0 - - # Really a trash metric unless sample sizes are huge. - count = 1200 - ident = self.mIdent - bl = [] - bl.append(deepcopy(self.blocks[ident].discoTimestamp)) - parent = self.blocks[ident].parent - count = count - 1 - while count > 0 and parent is not None: - ident = deepcopy(parent) - bl.append(deepcopy(self.blocks[ident].discoTimestamp)) - parent = self.blocks[ident].parent - count = count-1 - if len(bl) > 120: - sk = abs(skew(bl)) - va = var(bl) - stdv = sqrt(va) - lam = (1.0/stdv)*(2.0/sk)**(1.0/3.0) - else: - lam = targetRate # we will not change difficulty unless we have at least 120 blocks of data (arbitrarily selected) - self.diff = self.diff*(lam/targetRate) - elif mode=="reciprocalOfMedian": - # In this mode we use a bitcoin-style metric except instead of 1/average inter-arrival time - # we use 1/median magnitude of inter-arrival time. - # And updated each block like with monero instead of every 2016 blocks like bitcoin. - # We assume a sample size of only 600 blocks for now - count = 600 - interArrivals = [] - if len(self.blocks) < count: - estDiscoRate = targetRate - elif len(self.miningIdents) > 0: - ident = self.mIdent - parent = self.blocks[ident].parent - if parent is not None: - dT = abs(self.blocks[ident].discoTimestamp - self.blocks[parent].discoTimestamp) - interArrivals.append(dT) - count = count - 1 - touched = False - while count > 0 and parent is not None: - ident = deepcopy(parent) - parent = self.blocks[ident].parent - if parent is not None: - dT = abs(self.blocks[ident].discoTimestamp - self.blocks[parent].discoTimestamp) - interArrivals.append(dT) - count = count - 1 - touched = True - if not touched: - estDiscoRate = targetRate - else: - estDiscoRate = 1.0/median(interArrivals) - if self.verbose: - print("Est disco rate = " + str(estDiscoRate) + " and targetRate = " + str(targetRate)) - - - if self.verbose: - print("MLE discovery rate = " + str(estDiscoRate)) - print("Difficulty before adjustment = " + str(self.diff)) - - # Update difficulty multiplicatively - self.diff = self.diff*estDiscoRate/targetRate - - if self.verbose: - print("Difficulty after adjustment = ", str(self.diff)) - else: - print("Error, invalid difficulty mode entered.") - return result - -class Test_Blockchain(unittest.TestCase): - def test_addBlock(self): - bill = Blockchain([], verbosity=True) - mode="Nakamoto" - tr = 1.0/100.0 - bill.targetRate = tr - - name = newIdent(0) - t = time.time() - s = t+random.random() - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} - genesis = Block(params) - - self.assertEqual(genesis.ident,name) - self.assertEqual(genesis.discoTimestamp,t) - self.assertEqual(genesis.arrivTimestamp,s) - self.assertTrue(genesis.parent is None) - self.assertEqual(genesis.diff,diff) - - bill.addBlock(genesis, mode, tr) - - self.assertTrue(genesis.ident in bill.blocks) - self.assertTrue(genesis.ident in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(genesis.ident, bill.miningIdents[0]) - self.assertEqual(len(bill.blocks),1) - - name = newIdent(1) - t = time.time() - s = t+random.random() - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":genesis.ident, "diff":diff} - blockA = Block(params) - bill.addBlock(blockA, mode, tr) - - self.assertTrue(blockA.ident in bill.blocks) - self.assertTrue(blockA.ident in bill.leaves) - self.assertTrue(genesis.ident not in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(blockA.ident, bill.miningIdents[0]) - self.assertEqual(len(bill.blocks),2) - - - - - - bill = Blockchain([], verbosity=True) - mode="vanSaberhagen" - tr = 1.0/100.0 - bill.targetRate = tr - - name = newIdent(0) - t = time.time() - s = t+random.random() - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} - genesis = Block(params) - - self.assertEqual(genesis.ident,name) - self.assertEqual(genesis.discoTimestamp,t) - self.assertEqual(genesis.arrivTimestamp,s) - self.assertTrue(genesis.parent is None) - self.assertEqual(genesis.diff,diff) - - bill.addBlock(genesis, mode, tr) - - self.assertTrue(genesis.ident in bill.blocks) - self.assertTrue(genesis.ident in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(genesis.ident, bill.miningIdents[0]) - self.assertEqual(len(bill.blocks),1) - - name = newIdent(1) - t = time.time() - s = t+random.random() - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":genesis.ident, "diff":diff} - blockA = Block(params) - bill.addBlock(blockA, mode, tr) - - self.assertTrue(blockA.ident in bill.blocks) - self.assertTrue(blockA.ident in bill.leaves) - self.assertTrue(genesis.ident not in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(blockA.ident, bill.miningIdents[0]) - self.assertEqual(len(bill.blocks),2) - - - - - - bill = Blockchain([], verbosity=True) - mode="MOM:expModGauss" - tr = 1.0/100.0 - bill.targetRate = tr - - name = newIdent(0) - t = time.time() - s = t+random.random() - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} - genesis = Block(params) - - self.assertEqual(genesis.ident,name) - self.assertEqual(genesis.discoTimestamp,t) - self.assertEqual(genesis.arrivTimestamp,s) - self.assertTrue(genesis.parent is None) - self.assertEqual(genesis.diff,diff) - - bill.addBlock(genesis, mode, tr) - - self.assertTrue(genesis.ident in bill.blocks) - self.assertTrue(genesis.ident in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(genesis.ident, bill.miningIdents[0]) - self.assertEqual(len(bill.blocks),1) - - name = newIdent(1) - t = time.time() - s = t+random.random() - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":genesis.ident, "diff":diff} - blockA = Block(params) - bill.addBlock(blockA, mode, tr) - - self.assertTrue(blockA.ident in bill.blocks) - self.assertTrue(blockA.ident in bill.leaves) - self.assertTrue(genesis.ident not in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(blockA.ident, bill.miningIdents[0]) - self.assertEqual(len(bill.blocks),2) - - - def test_bc(self): - bill = Blockchain([], verbosity=True) - mode="Nakamoto" - tr = 1.0/100.0 - bill.targetRate = tr - - name = newIdent(0) - t = time.time() - s = t+1 - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} - genesis = Block(params) - - self.assertEqual(genesis.ident,name) - self.assertEqual(genesis.discoTimestamp,t) - self.assertEqual(genesis.arrivTimestamp,t+1) - self.assertTrue(genesis.parent is None) - self.assertEqual(genesis.diff,diff) - - bill.addBlock(genesis, mode, tr) - - self.assertTrue(genesis.ident in bill.blocks) - self.assertTrue(genesis.ident in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(genesis.ident, bill.miningIdents[0]) - - name = newIdent(1) - t = time.time() - s = t+1 - diff = 2.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":genesis.ident, "diff":diff} - blockA = Block(params) - bill.addBlock(blockA, mode, tr) - - #bill.whichLeaf() - - self.assertTrue(blockA.ident in bill.blocks) - self.assertTrue(blockA.ident in bill.leaves) - self.assertFalse(genesis.ident in bill.leaves) - self.assertTrue(genesis.ident in bill.blocks) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(blockA.ident, bill.miningIdents[0]) - - name = newIdent(1) - t = time.time() - s = t+1 - diff = 2.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":genesis.ident, "diff":diff} - blockB = Block(params) - bill.addBlock(blockB, mode, tr) - - self.assertTrue(blockB.ident in bill.blocks) - self.assertTrue(blockB.ident in bill.leaves) - self.assertEqual(bill.blocks[blockB.ident].parent, genesis.ident) - - self.assertTrue(blockA.ident in bill.blocks) - self.assertTrue(blockA.ident in bill.leaves) - self.assertEqual(bill.blocks[blockA.ident].parent, genesis.ident) - - self.assertTrue(genesis.ident in bill.blocks) - self.assertFalse(genesis.ident in bill.leaves) - self.assertTrue(bill.blocks[genesis.ident].parent is None) - - #bill.whichLeaf() - #print(bill.miningIdents) - - self.assertEqual(type(bill.miningIdents), type([])) - self.assertTrue(len(bill.miningIdents), 2) - - name = newIdent(2) - t = time.time() - diff = 3.14159 - params = {"ident":name, "disco":t, "arriv":s, "parent":blockB.ident, "diff":diff} - blockC = Block(params) - bill.addBlock(blockC, mode, tr) - - self.assertTrue(blockC.ident in bill.blocks) - self.assertTrue(blockC.ident in bill.leaves) - - self.assertTrue(blockB.ident in bill.blocks) - self.assertFalse(blockB.ident in bill.leaves) - - self.assertTrue(blockA.ident in bill.blocks) - self.assertTrue(blockA.ident in bill.leaves) - - self.assertTrue(genesis.ident in bill.blocks) - self.assertFalse(genesis.ident in bill.leaves) - - #bill.whichLeaf() - - #for blockIdent in bill.blocks: - # ident = bill.blocks[blockIdent].ident - # disco = bill.blocks[blockIdent].discoTimestamp - # arriv = bill.blocks[blockIdent].arrivTimestamp - # parent = bill.blocks[blockIdent].parent - # diff = bill.blocks[blockIdent].diff - # print(str(ident) + ", " + str(disco) + ", " + str(arriv) + ", " + str(parent) + ", " + str(diff) + ", " + str() + "\n") - #print(bill.miningIdents) - self.assertEqual(len(bill.miningIdents), 1) - self.assertEqual(bill.miningIdents[0], blockC.ident) - ''' - def test_median(self): - # TODO: everything. - mode = "reciprocalOfMedian" - tr = 1.0 # one block per millisecond why not - deltaT = 1.0 # let's just make this easy - bill = Blockchain([], verbosity=True) - bill.targetRate = tr - - with open("outputM.txt", "w") as writeFile: - # We will send (t, a, diff) to writeFile. - writeFile.write("time,rateConstant,difficulty\n") - name = newIdent(0) - t = 0.0 - s = 0.0 - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} - genesis = Block(params) - - self.assertEqual(genesis.ident,name) - self.assertEqual(genesis.discoTimestamp,t) - self.assertEqual(genesis.arrivTimestamp,s) - self.assertTrue(genesis.parent is None) - self.assertEqual(genesis.diff,diff) - - bill.addBlock(genesis, mode, tr) - a = 1.0 - b = 1.0/a - - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") - - self.assertTrue(genesis.ident in bill.blocks) - self.assertTrue(genesis.ident in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(genesis.ident, bill.miningIdents[0]) - - parent = genesis.ident - oldDiff = bill.diff - - while len(bill.blocks)<601: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - self.assertEqual(bill.diff, oldDiff) - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") - parent = newName - oldDiff = bill.diff - - a = 1.01 # slightly slower blocks, median won't change until half the data is corrupted! - b = 1.0/a - while len(bill.blocks)<899: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - self.assertEqual(bill.diff, oldDiff) - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - self.assertEqual(bill.diff, oldDiff) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") - parent = newName - oldDiff = bill.diff - - # One more block and our median inter-arrival time is deltaT*(1.0+a)/2.0 - # and so estRate = 1/median = (2.0/(1.0+a))/deltaT, whereas before it was just - # 1/deltaT. So estRate/targetRate = 2.0/(1.0+a) - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - self.assertEqual(bill.diff, oldDiff) - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - err = bill.diff - oldDiff*2.0/(1.0+a) - self.assertTrue(err*err < 10**-15) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") - parent = newName - oldDiff = bill.diff - - # One more block and our median inter-arrival time is deltaT*a - # and so estRate = 1/median = (1.0/a)/deltaT, whereas before it was just - # 1/deltaT. So estRate/targetRate = 1.0/a = b - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - self.assertEqual(bill.diff, oldDiff) - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - err = bill.diff - oldDiff*b - self.assertTrue(err*err < 10**-15) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") - parent = newName - oldDiff = bill.diff - - # Note that until the median changes again, this estimated block arrival rate - # does not change. This may be true even if a lot of new data has come in. - # It is possible that the same pair of blocks remain the median inter-arrival - # magnitude for the entire time both blocks are in the sample size. - # During this period of time, difficulty will update multiplicatively, so - # will either exponentially grow or shrink. - # In other words, this model can be looked at as: exponential change over - # time with a rate proportional to the deviation between the median and - # the target inter-arrival rates. - - - - - - def test_mine(self): - # TODO: everything. - mode = "MOM:expModGauss" - tr = 1.0/120000.0 # one block per two minutes - deltaT = 120000.0 - bill = Blockchain([], verbosity=True) - bill.targetRate = tr - - with open("outputM.txt", "w") as writeFile: - # We will send (t, a, diff, ratio, awayFromOne) to writeFile. - writeFile.write("time,rateConstant,difficulty\n") - name = newIdent(0) - t = 0.0 - s = 0.0 - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} - genesis = Block(params) - - self.assertEqual(genesis.ident,name) - self.assertEqual(genesis.discoTimestamp,t) - self.assertEqual(genesis.arrivTimestamp,s) - self.assertTrue(genesis.parent is None) - self.assertEqual(genesis.diff,diff) - - bill.addBlock(genesis, mode, tr) - a = 1.0 - b = 1.0/a - - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") - - self.assertTrue(genesis.ident in bill.blocks) - self.assertTrue(genesis.ident in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(genesis.ident, bill.miningIdents[0]) - - parent = genesis.ident - oldDiff = bill.diff - - while len(bill.blocks)<120: - # Our metric divides by skewness. In reality, this is zero with - # probability zero. But for our tests, it's assured. So we - # will perturb each arrival by a small, up-to-half-percent - # variation to ensure a nonzero skewness without altering things - # too much. - newName = newIdent(len(bill.blocks)) - t += deltaT*a*(1.0 + (2.0*random.random() - 1.0)/100.0) - s += deltaT*a*(1.0 + (2.0*random.random() - 1.0)/100.0) - self.assertEqual(bill.diff, oldDiff) - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") - parent = newName - oldDiff = bill.diff - - # Just one more block and difficulty should be computed for the first time. - print("Just one more block and difficulty should be computed for the first time.") - self.assertEqual(bill.diff, oldDiff) - newName = newIdent(len(bill.blocks)) - t += deltaT*a*(1.0 + (2.0*random.random() - 1.0)/100.0) - s += deltaT*a*(1.0 + (2.0*random.random() - 1.0)/100.0) - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") - parent = newName - #self.assertEqual(bill.diff, oldDiff) - - oldDiff = bill.diff - - # what if we add a bunch of blocks this way? - # In the case of a static hash rate, I suppose we hope to not - # vary too far from a multiplicative factor of 1.0, or rather - # a constant difficulty. - - while len(bill.blocks)<200: - # Our metric divides by skewness. In reality, this is zero with - # probability zero. But for our tests, it's assured. So we - # will perturb each arrival by a small, up-to-half-percent - # variation to ensure a nonzero skewness without altering things - # too much. - newName = newIdent(len(bill.blocks)) - t += deltaT*a*(1.0 + (2.0*random.random() - 1.0)/100.0) - s += deltaT*a*(1.0 + (2.0*random.random() - 1.0)/100.0) - self.assertEqual(bill.diff, oldDiff) - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") - parent = newName - oldDiff = bill.diff - - - - def test_vs(self): - # TODO: Still must test that outliers are being removed "appropriately" according to specifications - # TODO: Test that scrambled lists of timestamps produce the same difficulty estimate. - # TODO: Show that in the case of homogeneous poisson processes, unusual estimates are a little - # more common than in the Nakamoto difficulty (which must be the case because Nakamoto uses - # the UMVUE). - mode = "vanSaberhagen" - tr = 1.0/60000.0 # one block per minute - deltaT = 60000.0 - bill = Blockchain([], verbosity=True) - bill.targetRate = tr - - with open("output.txt", "w") as writeFile: - # We will send (t, a, diff, ratio, awayFromOne) to writeFile. - writeFile.write("time,rateConstant,difficulty,ratio\n") - name = newIdent(0) - t = 0.0 - s = 0.0 - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} - genesis = Block(params) - - self.assertEqual(genesis.ident,name) - self.assertEqual(genesis.discoTimestamp,t) - self.assertEqual(genesis.arrivTimestamp,s) - self.assertTrue(genesis.parent is None) - self.assertEqual(genesis.diff,diff) - - bill.addBlock(genesis, mode, tr) - writeFile.write(str(t) + ",1.0," + str(bill.diff) + ",1.0\n") - - self.assertTrue(genesis.ident in bill.blocks) - self.assertTrue(genesis.ident in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(genesis.ident, bill.miningIdents[0]) - self.assertEqual(bill.diff, 1.0) - - parent = genesis.ident - oldDiff = bill.diff - a = 1.0 - b = 1.0/a - - while len(bill.blocks)<120: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - self.assertEqual(bill.diff, oldDiff) - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - - writeFile.write(str(t) + ",1.0," + str(bill.diff) + ",1.0\n") - parent = newName - oldDiff = bill.diff - - # Just one more block and difficulty should be computed for the first time. - print("Just one more block and difficulty should be computed for the first time.") - self.assertEqual(bill.diff, oldDiff) - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - writeFile.write(str(t) + ",1.0," + str(bill.diff) + ",1.0\n") - parent = newName - self.assertEqual(bill.diff, oldDiff) - - oldDiff = bill.diff - - print("Let's add more blocks at the same rate.") - a = 1.0 - b = 1.0/a - - while len(bill.blocks)<1200: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - writeFile.write(str(t) + ",1.0," + str(bill.diff) + ",1.0\n") - parent = newName - self.assertEqual(bill.diff, oldDiff) - oldDiff = bill.diff - - print("Let's add more blocks at a slower rate.") - a = 1.1 - b = 1.0/a - - # If blocks arrive slightly further apart, difficulty should drop. - # However, since vanSaberhagen discards top 10% and bottom 10% of - # timestamps, it will take 120 blocks for this change to register - # in difficulty. - print("If blocks arrive slightly further apart, difficulty should drop. However, since vanSaberhagen discards top 10% and bottom 10% of timestamps, it will take 120 blocks for this change to register in difficulty.") - while len(bill.blocks)<1320: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "," + str(bill.diff/oldDiff) + "\n") - parent = newName - self.assertEqual(bill.diff, oldDiff) - oldDiff = bill.diff - - print("One more block and difficulty should register a change.") - self.assertEqual(bill.diff, oldDiff) - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "," + str(bill.diff/oldDiff) + "\n") - parent = newName - self.assertTrue(bill.diff < oldDiff) - oldDiff = bill.diff - - # Let's add another fifty blocks at this same rate and verify that difficulty continually - # drops. - print("Let's add another fifty blocks at this same rate and verify that difficulty continually drops.") - a = 1.1 - b = 1.0/a - - while len(bill.blocks)<1370: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "," + str(bill.diff/oldDiff) + "\n") - parent = newName - self.assertTrue(bill.diff < oldDiff) - oldDiff = bill.diff - - # Now we go back to the target rate. We have 170 slow blocks in the queue and 50 in the sample size. Difficulty will continue to drop for another 120 blocks... - print("Now we go back to the target rate. We have 170 slow blocks in the queue and 50 in the sample size. Difficulty will continue to drop for another 120 blocks...") - a = 1.0 - b = 1.0/a - - while len(bill.blocks)<1490: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "," + str(bill.diff/oldDiff) + "\n") - parent = newName - self.assertTrue(bill.diff < oldDiff) - oldRatio = bill.diff/oldDiff - oldDiff = bill.diff - #print(str(result) + ", " + str(bill.diff) + ", " + str(oldDiff)) - - # Now all 170 slow blocks are not only in the queue but in our sample. The *multiplicative factor* between timesteps should be identical for the next 790 blocks.. leading to AN EXPONENTIAL DECAY OF DIFFICULTY. - print("Now all 170 slow blocks are not only in the queue but in our sample. The *multiplicative factor* between timesteps should be identical for the next 790 blocks.. leading to AN EXPONENTIAL DECAY OF DIFFICULTY.") - a = 1.0 - b = 1.0/a - while len(bill.blocks)<2279: - newName = newIdent(len(bill.blocks)) - t += deltaT - s += deltaT - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "," + str(bill.diff/oldDiff) + "\n") - ratio = bill.diff/oldDiff - parent = newName - err = ratio - oldRatio - #print("Difference between last ratio and next ratio:" + str(err)) - self.assertTrue(err*err < 10**-15) - oldDiff = bill.diff - oldRatio = ratio - - print("Now adding a single new block will cause our 170 slow blocks to start dropping out of our sample, so the ratio should start returning to 1.0.") - oldAwayFromOne = abs(oldRatio - 1.0) # Ratio should be returning to 1.0 so this difference should go to zero - oldAwayFromOne = oldAwayFromOne*oldAwayFromOne - - # For the next 170 blocks as our perturbed blocks drop out of our sample, our - # estimated block arrival rate will return to "normal" so the multiplicative - # difference in difficulty should return to 1.0. - print("For the next 170 blocks as our perturbed blocks drop out of our sample, ourestimated block arrival rate will return to normal so the multiplicative difference in difficulty should return to 1.0.") - a = 1.0 - b = 1.0/a - while len(bill.blocks)<2449: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "," + str(bill.diff/oldDiff) + "\n") - ratio = bill.diff/oldDiff - #print("New ratio = " + str(ratio) + " and oldRatio = " + str(oldRatio)) - self.assertTrue(ratio > oldRatio) - awayFromOne = abs(ratio - 1.0) # Ratio should be returning to 1.0 so this difference should go to zero - awayFromOne = awayFromOne*awayFromOne - self.assertTrue(awayFromOne < oldAwayFromOne) # This return will be monotonic in our manufactured example. - parent = newName - oldDiff = bill.diff - oldRatio = ratio - oldAwayFromOne = awayFromOne - - - # Now difficulty should remain frozen for as long as we like. - - a = 1.0 - b = 1.0/a - while len(bill.blocks)<2500: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "," + str(bill.diff/oldDiff) + "\n") - parent = newName - self.assertEqual(bill.diff, oldDiff) - oldDiff = bill.diff - - - - - def test_nak(self): - # Since Nakamoto difficulty is derived from the MLE of the block arrival rate, - # we already know how it "should" behave in a poisson process, etc. - # TODO: Generate N samples of MLEs of Poisson rates compared to known homog. - # poisson rate, show that the resulting code does not result in unusual measurements - # more often than expected. - mode = "Nakamoto" - tr = 1.0/600000.0 - deltaT = 600000.0 - bill = Blockchain([], verbosity=True) - bill.targetRate = tr - # Bitcoin updating at 1 block per 10 minutes - - name = newIdent(0) - t = 0.0 - s = 0.0 - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} - genesis = Block(params) - - self.assertEqual(genesis.ident,name) - self.assertEqual(genesis.discoTimestamp,t) - self.assertEqual(genesis.arrivTimestamp,s) - self.assertTrue(genesis.parent is None) - self.assertEqual(genesis.diff,diff) - - bill.addBlock(genesis, mode, tr) - - self.assertTrue(genesis.ident in bill.blocks) - self.assertTrue(genesis.ident in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(genesis.ident, bill.miningIdents[0]) - self.assertEqual(bill.diff, 1.0) - - parent = genesis.ident - oldDiff = bill.diff - i = 1 - - while len(bill.blocks)<2016*i-1: - newName = newIdent(len(bill.blocks)) - t += deltaT - s += deltaT - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - parent = newName - - # Just one more block and difficulty should recompute. - print("Just one more block and difficulty should recompute.") - self.assertEqual(bill.diff, oldDiff) - newName = newIdent(len(bill.blocks)) - t += deltaT - s += deltaT - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - parent = newName - self.assertEqual(bill.diff, oldDiff) - - oldDiff = bill.diff - i += 1 - - while len(bill.blocks)<2016*i-1: - newName = newIdent(len(bill.blocks)) - t += deltaT - s += deltaT - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - parent = newName - - # Just one more block and difficulty should recompute. - print("Just one more block and difficulty should again recompute.") - self.assertEqual(bill.diff, oldDiff) - newName = newIdent(len(bill.blocks)) - t += deltaT - s += deltaT - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - parent = newName - self.assertEqual(bill.diff, oldDiff) - - oldDiff = bill.diff - i += 1 - a = 1.1 - b = 1.0/a - - # If blocks arrive slightly further apart, difficulty should drop. - while len(bill.blocks)<2016*i-1: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - parent = newName - - print("Just one more block and difficulty will go down.") - - self.assertEqual(bill.diff, oldDiff) - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - parent = newName - err = abs(bill.diff - oldDiff*b) - self.assertTrue(err*err < 10**-15) - oldDiff = bill.diff - i += 1 - - - # If blocks then arrive on target, difficulty should freeze. - a = 1.0 - b = 1.0/a - while len(bill.blocks)<2016*i-1: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - parent = newName - - self.assertEqual(bill.diff, oldDiff) - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - parent = newName - self.assertEqual(bill.diff, oldDiff) - oldDiff = bill.diff - i += 1 - - # If blocks arrive too close together, difficulty should increase. - a = 0.9 - b = 1.0/a - while len(bill.blocks)<2016*i-1: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - parent = newName - - print("Just one more block and difficulty should go up.") - self.assertEqual(bill.diff, oldDiff) - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - parent = newName - err = abs(bill.diff - oldDiff*b) - self.assertTrue(err*err < 10**-15) - ''' - - - - -suite = unittest.TestLoader().loadTestsFromTestCase(Test_Blockchain) -unittest.TextTestRunner(verbosity=1).run(suite) diff --git a/source-code/Poisson-Graphs/new/Blockchain.py~ b/source-code/Poisson-Graphs/new/Blockchain.py~ deleted file mode 100644 index 97a3ba2..0000000 --- a/source-code/Poisson-Graphs/new/Blockchain.py~ +++ /dev/null @@ -1,1142 +0,0 @@ -from Block import * -import math -from scipy.stats import * -from numpy import * -from copy import deepcopy - -class Blockchain(object): - ''' - Not a true blockchain, of course, but tracks block objects (timestamps) as above. - Each node should be responsible for finding the chain with most cumulative work. - Right now we assume Nakamoto consensus (konsensnakamoto). - ''' - def __init__(self, params=[], verbosity=True): - self.blocks = {} - self.leaves = {} - self.miningIdents = None - self.mIdent = None - self.verbose = verbosity - self.diff = None - self.targetRate = None - - def addBlock(self, blockToAdd, mode="Nakamoto", targetRate=1.0/600000.0): - # In our model we assume difficulty scores of blocks are correct (otherwise they would - # be rejected in the real life network, and we aren't trying to model spam attacks). - assert blockToAdd.ident not in self.blocks - if len(self.blocks)==0: - # In this case, blockToAdd is a genesis block, so we set difficulty - self.diff = deepcopy(blockToAdd.diff) - - self.blocks.update({blockToAdd.ident:blockToAdd}) - self.leaves.update({blockToAdd.ident:blockToAdd}) - if blockToAdd.parent in self.leaves: - del self.leaves[blockToAdd.parent] - self.whichLeaf() - return self.computeDifficulty(mode, targetRate) - - def whichLeaf(self): - # Determine which leaf shall be the parent leaf. - # If the chain has forked *ever* this will not be the case. - maxCumDiff = 0.0 - self.miningIdents = [] - for ident in self.leaves: - tempCumDiff = 0.0 - thisBlockIdent = ident - tempCumDiff += self.blocks[thisBlockIdent].diff - while self.blocks[thisBlockIdent].parent is not None: - thisBlockIdent = self.blocks[thisBlockIdent].parent - tempCumDiff += self.blocks[thisBlockIdent].diff - if tempCumDiff > maxCumDiff: - # If more than one leaf ties for maxCumDiff, each node in the - # network should pick one of these two arbitrarily. Since we - # are storing each blockchain in a hash table (unordered!), for - # each node in the network that observes a tie, each possible leaf - # is equally likely to have been the first one found! So - # we don't need to do anything for the node to select which chain - # to work off of. - self.miningIdents = [ident] - maxCumDiff = tempCumDiff - elif tempCumDiff == maxCumDiff: - self.miningIdents.append(ident) - #print("leaf ident = ", str(ident), ", and tempCumDiff = ", str(tempCumDiff), " and maxCumDiff = ", str(maxCumDiff)) - assert len(self.miningIdents) > 0 - self.mIdent = random.choice(self.miningIdents) - - - # 1 block in 6*10^5 milliseconds=10min - def computeDifficulty(self, mode="Nakamoto", targetRate=1.0/600000.0): - result = None - if mode=="Nakamoto": - # Use MLE estimate of poisson process, compare to targetRate, update by multiplying by resulting ratio. - #if self.verbose: - # print("Beginning update of difficulty with Nakamoto method") - count = 2016 - #if self.verbose: - # print("Checking that blockchain is 2016*n blocks long and some mining identity has been set") - if len(self.blocks) % 2016 == 0 and len(self.miningIdents) > 0: - ident = self.mIdent - topTime = deepcopy(self.blocks[ident].discoTimestamp) - parent = self.blocks[ident].parent - count = count - 1 - touched = False - while count > 0 and parent is not None: - ident = deepcopy(parent) - parent = self.blocks[ident].parent - count = count - 1 - touched = True - if not touched: - mleDiscoRate = targetRate - else: - botTime = deepcopy(self.blocks[ident].discoTimestamp) - - # Algebra is okay: - assert topTime != botTime - - # MLE estimate of arrivals per second: - mleDiscoRate = float(2015)/float(topTime - botTime) - - # Rates can't be negative, but this estimate could be (although it's highly unlikely given Bitcoin's standard choices - # of difficulty update rate, etc. - mleDiscoRate = abs(mleDiscoRate) - - if self.verbose: - print("MLE disco rate = " + str(mleDiscoRate) + " and targetRate = " + str(targetRate)) - # Rate must be positive... so the MLE for block arrival rate - # assuming a Poisson process _is not even well-defined_ as - # an estimate for block arrival rate assuming timestamps are - # inaccurately reported! - - # We use it nonetheless. - - if self.verbose: - print("MLE discovery rate = " + str(mleDiscoRate)) - print("Difficulty before adjustment = " + str(self.diff)) - - # Update difficulty multiplicatively - self.diff = self.diff*mleDiscoRate/targetRate - - if self.verbose: - print("Difficulty after adjustment = ", str(self.diff)) - - elif mode=="vanSaberhagen": - # Similar to above, except use 1200 blocks, discard top 120 and bottom 120 after sorting. - # 4 minute blocks in the original cryptonote, I believe... targetRate = 1.0/ - # 4 minutes/period, 60 seconds/minute ~ 240 seconds/period - # assert targetRate==1.0/240.0 - count = 1200 - #print(self.diff) - assert self.diff != 0.0 - if len(self.blocks) > 120 and len(self.miningIdents) > 0: - ident = self.mIdent - bl = [] - bl.append(deepcopy(self.blocks[ident].discoTimestamp)) - parent = self.blocks[ident].parent - count = count - 1 - while count > 0 and parent is not None: - ident = deepcopy(parent) - bl.append(deepcopy(self.blocks[ident].discoTimestamp)) - parent = self.blocks[ident].parent - count = count-1 - # sort - bl = sorted(bl) - assert len(bl)<=1200 - - #print("Sample size = " + str(len(bl))) - # remove 10 and 90 %-iles - numOutliers = math.ceil(float(len(bl))/float(10)) - assert numOutliers <= 120 - #print("Number of outliers = " + str(numOutliers)) - oldBL = deepcopy(bl) - if numOutliers > 0: - bl = bl[numOutliers:-numOutliers] - #if numOutliers == 120: - # print("\n\nSORTED TS LIST = " + str(oldBL) + "\nModified list = " + str(bl)) - - - # get topTime and botTime - #if self.verbose: - # print("bl[0] = " + str(bl[0]) + ",\tbl[-1] = " + str(bl[-1])) - topTime = bl[-1] - botTime = bl[0] - result = [float(topTime - botTime)] - #print(topTime - botTime) - #if self.verbose: - # print("list of timestamps = " + str(bl)) - # print("topTime = " + str(bl[-1])) - # print("botTime = " + str(bl[0])) - - # Assert algebra will work - # 1200 - 2*120 = 1200 - 240 = 960 - assert 0 < len(bl) and len(bl) < 961 - assert topTime - botTime >= 0.0 - result.append(len(bl)-1) - # Sort of the MLE: # blocks/difference in reported times - # But not the MLE, since the reported times may not be - # the actual times, the "difference in reported times" != - # "ground truth difference in block discoery times" in general - if len(bl)==0: - print("WOOP WOOP NO TIMESTAMPS WTF? We have " + str(len(self.blocks)) + " blocks available, and we are counting " + str(2*numOutliers) + " as outliers. bl = " + str(bl)) - naiveDiscoRate = float(len(bl)-1)/float(topTime - botTime) - - # How much should difficulty change? - assert naiveDiscoRate != 0.0 - assert targetRate != 0.0 - assert self.diff != 0.0 - self.diff = self.diff*naiveDiscoRate/targetRate - - elif mode=="MOM:expModGauss": - # Similar to "vanSaberhagen" except with 2-minute blocks and - # we attempt to take into account that "difference in timestamps" - # can be negative by: - # 1) insisting that the ordering induced by the blockchain and - # 2) modeling timestamps as exponentially modified gaussian. - # If timestamps are T = X + Z where X is exponentially dist- - # ributed with parameter lambda and Z is some Gaussian - # noise with average mu and variance sigma2, then we can est- - # imate sigma2, mu, and lambda: - # mu ~ mean - stdev*(skewness/2)**(1.0/3.0) - # sigma2 ~ variance*(1-(skewness/2)**(2.0/3.0)) - # lambda ~ (1.0/(stdev))*(2/skewness)**(1.0/3.0) - #assert targetRate==1.0/120.0 - - # Really a trash metric unless sample sizes are huge. - count = 1200 - ident = self.mIdent - bl = [] - bl.append(deepcopy(self.blocks[ident].discoTimestamp)) - parent = self.blocks[ident].parent - count = count - 1 - while count > 0 and parent is not None: - ident = deepcopy(parent) - bl.append(deepcopy(self.blocks[ident].discoTimestamp)) - parent = self.blocks[ident].parent - count = count-1 - if len(bl) > 120: - sk = abs(skew(bl)) - va = var(bl) - stdv = sqrt(va) - lam = (1.0/stdv)*(2.0/sk)**(1.0/3.0) - else: - lam = targetRate # we will not change difficulty unless we have at least 120 blocks of data (arbitrarily selected) - self.diff = self.diff*(lam/targetRate) - elif mode=="reciprocalOfMedian": - # In this mode we use a bitcoin-style metric except instead of 1/average inter-arrival time - # we use 1/median magnitude of inter-arrival time. - # And updated each block like with monero instead of every 2016 blocks like bitcoin. - # We assume a sample size of only 600 blocks for now - count = 600 - interArrivals = [] - if len(self.blocks) < count: - estDiscoRate = targetRate - elif len(self.miningIdents) > 0: - ident = self.mIdent - parent = self.blocks[ident].parent - if parent is not None: - dT = abs(self.blocks[ident].discoTimestamp - self.blocks[parent].discoTimestamp) - interArrivals.append(dT) - count = count - 1 - touched = False - while count > 0 and parent is not None: - ident = deepcopy(parent) - parent = self.blocks[ident].parent - if parent is not None: - dT = abs(self.blocks[ident].discoTimestamp - self.blocks[parent].discoTimestamp) - interArrivals.append(dT) - count = count - 1 - touched = True - if not touched: - estDiscoRate = targetRate - else: - estDiscoRate = 1.0/median(interArrivals) - if self.verbose: - print("Est disco rate = " + str(estDiscoRate) + " and targetRate = " + str(targetRate)) - - - if self.verbose: - print("MLE discovery rate = " + str(estDiscoRate)) - print("Difficulty before adjustment = " + str(self.diff)) - - # Update difficulty multiplicatively - self.diff = self.diff*estDiscoRate/targetRate - - if self.verbose: - print("Difficulty after adjustment = ", str(self.diff)) - else: - print("Error, invalid difficulty mode entered.") - return result - -class Test_Blockchain(unittest.TestCase): - def test_addBlock(self): - bill = Blockchain([], verbosity=True) - mode="Nakamoto" - tr = 1.0/100.0 - bill.targetRate = tr - - name = newIdent(0) - t = time.time() - s = t+random.random() - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} - genesis = Block(params) - - self.assertEqual(genesis.ident,name) - self.assertEqual(genesis.discoTimestamp,t) - self.assertEqual(genesis.arrivTimestamp,s) - self.assertTrue(genesis.parent is None) - self.assertEqual(genesis.diff,diff) - - bill.addBlock(genesis, mode, tr) - - self.assertTrue(genesis.ident in bill.blocks) - self.assertTrue(genesis.ident in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(genesis.ident, bill.miningIdents[0]) - self.assertEqual(len(bill.blocks),1) - - name = newIdent(1) - t = time.time() - s = t+random.random() - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":genesis.ident, "diff":diff} - blockA = Block(params) - bill.addBlock(blockA, mode, tr) - - self.assertTrue(blockA.ident in bill.blocks) - self.assertTrue(blockA.ident in bill.leaves) - self.assertTrue(genesis.ident not in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(blockA.ident, bill.miningIdents[0]) - self.assertEqual(len(bill.blocks),2) - - - - - - bill = Blockchain([], verbosity=True) - mode="vanSaberhagen" - tr = 1.0/100.0 - bill.targetRate = tr - - name = newIdent(0) - t = time.time() - s = t+random.random() - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} - genesis = Block(params) - - self.assertEqual(genesis.ident,name) - self.assertEqual(genesis.discoTimestamp,t) - self.assertEqual(genesis.arrivTimestamp,s) - self.assertTrue(genesis.parent is None) - self.assertEqual(genesis.diff,diff) - - bill.addBlock(genesis, mode, tr) - - self.assertTrue(genesis.ident in bill.blocks) - self.assertTrue(genesis.ident in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(genesis.ident, bill.miningIdents[0]) - self.assertEqual(len(bill.blocks),1) - - name = newIdent(1) - t = time.time() - s = t+random.random() - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":genesis.ident, "diff":diff} - blockA = Block(params) - bill.addBlock(blockA, mode, tr) - - self.assertTrue(blockA.ident in bill.blocks) - self.assertTrue(blockA.ident in bill.leaves) - self.assertTrue(genesis.ident not in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(blockA.ident, bill.miningIdents[0]) - self.assertEqual(len(bill.blocks),2) - - - - - - bill = Blockchain([], verbosity=True) - mode="MOM:expModGauss" - tr = 1.0/100.0 - bill.targetRate = tr - - name = newIdent(0) - t = time.time() - s = t+random.random() - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} - genesis = Block(params) - - self.assertEqual(genesis.ident,name) - self.assertEqual(genesis.discoTimestamp,t) - self.assertEqual(genesis.arrivTimestamp,s) - self.assertTrue(genesis.parent is None) - self.assertEqual(genesis.diff,diff) - - bill.addBlock(genesis, mode, tr) - - self.assertTrue(genesis.ident in bill.blocks) - self.assertTrue(genesis.ident in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(genesis.ident, bill.miningIdents[0]) - self.assertEqual(len(bill.blocks),1) - - name = newIdent(1) - t = time.time() - s = t+random.random() - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":genesis.ident, "diff":diff} - blockA = Block(params) - bill.addBlock(blockA, mode, tr) - - self.assertTrue(blockA.ident in bill.blocks) - self.assertTrue(blockA.ident in bill.leaves) - self.assertTrue(genesis.ident not in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(blockA.ident, bill.miningIdents[0]) - self.assertEqual(len(bill.blocks),2) - - - def test_bc(self): - bill = Blockchain([], verbosity=True) - mode="Nakamoto" - tr = 1.0/100.0 - bill.targetRate = tr - - name = newIdent(0) - t = time.time() - s = t+1 - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} - genesis = Block(params) - - self.assertEqual(genesis.ident,name) - self.assertEqual(genesis.discoTimestamp,t) - self.assertEqual(genesis.arrivTimestamp,t+1) - self.assertTrue(genesis.parent is None) - self.assertEqual(genesis.diff,diff) - - bill.addBlock(genesis, mode, tr) - - self.assertTrue(genesis.ident in bill.blocks) - self.assertTrue(genesis.ident in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(genesis.ident, bill.miningIdents[0]) - - name = newIdent(1) - t = time.time() - s = t+1 - diff = 2.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":genesis.ident, "diff":diff} - blockA = Block(params) - bill.addBlock(blockA, mode, tr) - - #bill.whichLeaf() - - self.assertTrue(blockA.ident in bill.blocks) - self.assertTrue(blockA.ident in bill.leaves) - self.assertFalse(genesis.ident in bill.leaves) - self.assertTrue(genesis.ident in bill.blocks) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(blockA.ident, bill.miningIdents[0]) - - name = newIdent(1) - t = time.time() - s = t+1 - diff = 2.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":genesis.ident, "diff":diff} - blockB = Block(params) - bill.addBlock(blockB, mode, tr) - - self.assertTrue(blockB.ident in bill.blocks) - self.assertTrue(blockB.ident in bill.leaves) - self.assertEqual(bill.blocks[blockB.ident].parent, genesis.ident) - - self.assertTrue(blockA.ident in bill.blocks) - self.assertTrue(blockA.ident in bill.leaves) - self.assertEqual(bill.blocks[blockA.ident].parent, genesis.ident) - - self.assertTrue(genesis.ident in bill.blocks) - self.assertFalse(genesis.ident in bill.leaves) - self.assertTrue(bill.blocks[genesis.ident].parent is None) - - #bill.whichLeaf() - #print(bill.miningIdents) - - self.assertEqual(type(bill.miningIdents), type([])) - self.assertTrue(len(bill.miningIdents), 2) - - name = newIdent(2) - t = time.time() - diff = 3.14159 - params = {"ident":name, "disco":t, "arriv":s, "parent":blockB.ident, "diff":diff} - blockC = Block(params) - bill.addBlock(blockC, mode, tr) - - self.assertTrue(blockC.ident in bill.blocks) - self.assertTrue(blockC.ident in bill.leaves) - - self.assertTrue(blockB.ident in bill.blocks) - self.assertFalse(blockB.ident in bill.leaves) - - self.assertTrue(blockA.ident in bill.blocks) - self.assertTrue(blockA.ident in bill.leaves) - - self.assertTrue(genesis.ident in bill.blocks) - self.assertFalse(genesis.ident in bill.leaves) - - #bill.whichLeaf() - - #for blockIdent in bill.blocks: - # ident = bill.blocks[blockIdent].ident - # disco = bill.blocks[blockIdent].discoTimestamp - # arriv = bill.blocks[blockIdent].arrivTimestamp - # parent = bill.blocks[blockIdent].parent - # diff = bill.blocks[blockIdent].diff - # print(str(ident) + ", " + str(disco) + ", " + str(arriv) + ", " + str(parent) + ", " + str(diff) + ", " + str() + "\n") - #print(bill.miningIdents) - self.assertEqual(len(bill.miningIdents), 1) - self.assertEqual(bill.miningIdents[0], blockC.ident) - ''' - def test_median(self): - # TODO: everything. - mode = "reciprocalOfMedian" - tr = 1.0 # one block per millisecond why not - deltaT = 1.0 # let's just make this easy - bill = Blockchain([], verbosity=True) - bill.targetRate = tr - - with open("outputM.txt", "w") as writeFile: - # We will send (t, a, diff) to writeFile. - writeFile.write("time,rateConstant,difficulty\n") - name = newIdent(0) - t = 0.0 - s = 0.0 - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} - genesis = Block(params) - - self.assertEqual(genesis.ident,name) - self.assertEqual(genesis.discoTimestamp,t) - self.assertEqual(genesis.arrivTimestamp,s) - self.assertTrue(genesis.parent is None) - self.assertEqual(genesis.diff,diff) - - bill.addBlock(genesis, mode, tr) - a = 1.0 - b = 1.0/a - - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") - - self.assertTrue(genesis.ident in bill.blocks) - self.assertTrue(genesis.ident in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(genesis.ident, bill.miningIdents[0]) - - parent = genesis.ident - oldDiff = bill.diff - - while len(bill.blocks)<601: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - self.assertEqual(bill.diff, oldDiff) - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") - parent = newName - oldDiff = bill.diff - - a = 1.01 # slightly slower blocks, median won't change until half the data is corrupted! - b = 1.0/a - while len(bill.blocks)<899: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - self.assertEqual(bill.diff, oldDiff) - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - self.assertEqual(bill.diff, oldDiff) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") - parent = newName - oldDiff = bill.diff - - # One more block and our median inter-arrival time is deltaT*(1.0+a)/2.0 - # and so estRate = 1/median = (2.0/(1.0+a))/deltaT, whereas before it was just - # 1/deltaT. So estRate/targetRate = 2.0/(1.0+a) - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - self.assertEqual(bill.diff, oldDiff) - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - err = bill.diff - oldDiff*2.0/(1.0+a) - self.assertTrue(err*err < 10**-15) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") - parent = newName - oldDiff = bill.diff - - # One more block and our median inter-arrival time is deltaT*a - # and so estRate = 1/median = (1.0/a)/deltaT, whereas before it was just - # 1/deltaT. So estRate/targetRate = 1.0/a = b - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - self.assertEqual(bill.diff, oldDiff) - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - err = bill.diff - oldDiff*b - self.assertTrue(err*err < 10**-15) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") - parent = newName - oldDiff = bill.diff - - # Note that until the median changes again, this estimated block arrival rate - # does not change. This may be true even if a lot of new data has come in. - # It is possible that the same pair of blocks remain the median inter-arrival - # magnitude for the entire time both blocks are in the sample size. - # During this period of time, difficulty will update multiplicatively, so - # will either exponentially grow or shrink. - # In other words, this model can be looked at as: exponential change over - # time with a rate proportional to the deviation between the median and - # the target inter-arrival rates. - - - - - - def test_mine(self): - # TODO: everything. - mode = "MOM:expModGauss" - tr = 1.0/120000.0 # one block per two minutes - deltaT = 120000.0 - bill = Blockchain([], verbosity=True) - bill.targetRate = tr - - with open("outputM.txt", "w") as writeFile: - # We will send (t, a, diff, ratio, awayFromOne) to writeFile. - writeFile.write("time,rateConstant,difficulty\n") - name = newIdent(0) - t = 0.0 - s = 0.0 - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} - genesis = Block(params) - - self.assertEqual(genesis.ident,name) - self.assertEqual(genesis.discoTimestamp,t) - self.assertEqual(genesis.arrivTimestamp,s) - self.assertTrue(genesis.parent is None) - self.assertEqual(genesis.diff,diff) - - bill.addBlock(genesis, mode, tr) - a = 1.0 - b = 1.0/a - - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") - - self.assertTrue(genesis.ident in bill.blocks) - self.assertTrue(genesis.ident in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(genesis.ident, bill.miningIdents[0]) - - parent = genesis.ident - oldDiff = bill.diff - - while len(bill.blocks)<120: - # Our metric divides by skewness. In reality, this is zero with - # probability zero. But for our tests, it's assured. So we - # will perturb each arrival by a small, up-to-half-percent - # variation to ensure a nonzero skewness without altering things - # too much. - newName = newIdent(len(bill.blocks)) - t += deltaT*a*(1.0 + (2.0*random.random() - 1.0)/100.0) - s += deltaT*a*(1.0 + (2.0*random.random() - 1.0)/100.0) - self.assertEqual(bill.diff, oldDiff) - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") - parent = newName - oldDiff = bill.diff - - # Just one more block and difficulty should be computed for the first time. - print("Just one more block and difficulty should be computed for the first time.") - self.assertEqual(bill.diff, oldDiff) - newName = newIdent(len(bill.blocks)) - t += deltaT*a*(1.0 + (2.0*random.random() - 1.0)/100.0) - s += deltaT*a*(1.0 + (2.0*random.random() - 1.0)/100.0) - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") - parent = newName - #self.assertEqual(bill.diff, oldDiff) - - oldDiff = bill.diff - - # what if we add a bunch of blocks this way? - # In the case of a static hash rate, I suppose we hope to not - # vary too far from a multiplicative factor of 1.0, or rather - # a constant difficulty. - - while len(bill.blocks)<200: - # Our metric divides by skewness. In reality, this is zero with - # probability zero. But for our tests, it's assured. So we - # will perturb each arrival by a small, up-to-half-percent - # variation to ensure a nonzero skewness without altering things - # too much. - newName = newIdent(len(bill.blocks)) - t += deltaT*a*(1.0 + (2.0*random.random() - 1.0)/100.0) - s += deltaT*a*(1.0 + (2.0*random.random() - 1.0)/100.0) - self.assertEqual(bill.diff, oldDiff) - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "\n") - parent = newName - oldDiff = bill.diff - - - - def test_vs(self): - # TODO: Still must test that outliers are being removed "appropriately" according to specifications - # TODO: Test that scrambled lists of timestamps produce the same difficulty estimate. - # TODO: Show that in the case of homogeneous poisson processes, unusual estimates are a little - # more common than in the Nakamoto difficulty (which must be the case because Nakamoto uses - # the UMVUE). - mode = "vanSaberhagen" - tr = 1.0/60000.0 # one block per minute - deltaT = 60000.0 - bill = Blockchain([], verbosity=True) - bill.targetRate = tr - - with open("output.txt", "w") as writeFile: - # We will send (t, a, diff, ratio, awayFromOne) to writeFile. - writeFile.write("time,rateConstant,difficulty,ratio\n") - name = newIdent(0) - t = 0.0 - s = 0.0 - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} - genesis = Block(params) - - self.assertEqual(genesis.ident,name) - self.assertEqual(genesis.discoTimestamp,t) - self.assertEqual(genesis.arrivTimestamp,s) - self.assertTrue(genesis.parent is None) - self.assertEqual(genesis.diff,diff) - - bill.addBlock(genesis, mode, tr) - writeFile.write(str(t) + ",1.0," + str(bill.diff) + ",1.0\n") - - self.assertTrue(genesis.ident in bill.blocks) - self.assertTrue(genesis.ident in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(genesis.ident, bill.miningIdents[0]) - self.assertEqual(bill.diff, 1.0) - - parent = genesis.ident - oldDiff = bill.diff - a = 1.0 - b = 1.0/a - - while len(bill.blocks)<120: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - self.assertEqual(bill.diff, oldDiff) - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - - writeFile.write(str(t) + ",1.0," + str(bill.diff) + ",1.0\n") - parent = newName - oldDiff = bill.diff - - # Just one more block and difficulty should be computed for the first time. - print("Just one more block and difficulty should be computed for the first time.") - self.assertEqual(bill.diff, oldDiff) - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - writeFile.write(str(t) + ",1.0," + str(bill.diff) + ",1.0\n") - parent = newName - self.assertEqual(bill.diff, oldDiff) - - oldDiff = bill.diff - - print("Let's add more blocks at the same rate.") - a = 1.0 - b = 1.0/a - - while len(bill.blocks)<1200: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - writeFile.write(str(t) + ",1.0," + str(bill.diff) + ",1.0\n") - parent = newName - self.assertEqual(bill.diff, oldDiff) - oldDiff = bill.diff - - print("Let's add more blocks at a slower rate.") - a = 1.1 - b = 1.0/a - - # If blocks arrive slightly further apart, difficulty should drop. - # However, since vanSaberhagen discards top 10% and bottom 10% of - # timestamps, it will take 120 blocks for this change to register - # in difficulty. - print("If blocks arrive slightly further apart, difficulty should drop. However, since vanSaberhagen discards top 10% and bottom 10% of timestamps, it will take 120 blocks for this change to register in difficulty.") - while len(bill.blocks)<1320: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "," + str(bill.diff/oldDiff) + "\n") - parent = newName - self.assertEqual(bill.diff, oldDiff) - oldDiff = bill.diff - - print("One more block and difficulty should register a change.") - self.assertEqual(bill.diff, oldDiff) - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "," + str(bill.diff/oldDiff) + "\n") - parent = newName - self.assertTrue(bill.diff < oldDiff) - oldDiff = bill.diff - - # Let's add another fifty blocks at this same rate and verify that difficulty continually - # drops. - print("Let's add another fifty blocks at this same rate and verify that difficulty continually drops.") - a = 1.1 - b = 1.0/a - - while len(bill.blocks)<1370: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "," + str(bill.diff/oldDiff) + "\n") - parent = newName - self.assertTrue(bill.diff < oldDiff) - oldDiff = bill.diff - - # Now we go back to the target rate. We have 170 slow blocks in the queue and 50 in the sample size. Difficulty will continue to drop for another 120 blocks... - print("Now we go back to the target rate. We have 170 slow blocks in the queue and 50 in the sample size. Difficulty will continue to drop for another 120 blocks...") - a = 1.0 - b = 1.0/a - - while len(bill.blocks)<1490: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "," + str(bill.diff/oldDiff) + "\n") - parent = newName - self.assertTrue(bill.diff < oldDiff) - oldRatio = bill.diff/oldDiff - oldDiff = bill.diff - #print(str(result) + ", " + str(bill.diff) + ", " + str(oldDiff)) - - # Now all 170 slow blocks are not only in the queue but in our sample. The *multiplicative factor* between timesteps should be identical for the next 790 blocks.. leading to AN EXPONENTIAL DECAY OF DIFFICULTY. - print("Now all 170 slow blocks are not only in the queue but in our sample. The *multiplicative factor* between timesteps should be identical for the next 790 blocks.. leading to AN EXPONENTIAL DECAY OF DIFFICULTY.") - a = 1.0 - b = 1.0/a - while len(bill.blocks)<2279: - newName = newIdent(len(bill.blocks)) - t += deltaT - s += deltaT - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "," + str(bill.diff/oldDiff) + "\n") - ratio = bill.diff/oldDiff - parent = newName - err = ratio - oldRatio - #print("Difference between last ratio and next ratio:" + str(err)) - self.assertTrue(err*err < 10**-15) - oldDiff = bill.diff - oldRatio = ratio - - print("Now adding a single new block will cause our 170 slow blocks to start dropping out of our sample, so the ratio should start returning to 1.0.") - oldAwayFromOne = abs(oldRatio - 1.0) # Ratio should be returning to 1.0 so this difference should go to zero - oldAwayFromOne = oldAwayFromOne*oldAwayFromOne - - # For the next 170 blocks as our perturbed blocks drop out of our sample, our - # estimated block arrival rate will return to "normal" so the multiplicative - # difference in difficulty should return to 1.0. - print("For the next 170 blocks as our perturbed blocks drop out of our sample, ourestimated block arrival rate will return to normal so the multiplicative difference in difficulty should return to 1.0.") - a = 1.0 - b = 1.0/a - while len(bill.blocks)<2449: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "," + str(bill.diff/oldDiff) + "\n") - ratio = bill.diff/oldDiff - #print("New ratio = " + str(ratio) + " and oldRatio = " + str(oldRatio)) - self.assertTrue(ratio > oldRatio) - awayFromOne = abs(ratio - 1.0) # Ratio should be returning to 1.0 so this difference should go to zero - awayFromOne = awayFromOne*awayFromOne - self.assertTrue(awayFromOne < oldAwayFromOne) # This return will be monotonic in our manufactured example. - parent = newName - oldDiff = bill.diff - oldRatio = ratio - oldAwayFromOne = awayFromOne - - - # Now difficulty should remain frozen for as long as we like. - - a = 1.0 - b = 1.0/a - while len(bill.blocks)<2500: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - writeFile.write(str(t) + "," + str(a) + "," + str(bill.diff) + "," + str(bill.diff/oldDiff) + "\n") - parent = newName - self.assertEqual(bill.diff, oldDiff) - oldDiff = bill.diff - - - - - def test_nak(self): - # Since Nakamoto difficulty is derived from the MLE of the block arrival rate, - # we already know how it "should" behave in a poisson process, etc. - # TODO: Generate N samples of MLEs of Poisson rates compared to known homog. - # poisson rate, show that the resulting code does not result in unusual measurements - # more often than expected. - mode = "Nakamoto" - tr = 1.0/600000.0 - deltaT = 600000.0 - bill = Blockchain([], verbosity=True) - bill.targetRate = tr - # Bitcoin updating at 1 block per 10 minutes - - name = newIdent(0) - t = 0.0 - s = 0.0 - diff = 1.0 - params = {"ident":name, "disco":t, "arriv":s, "parent":None, "diff":diff} - genesis = Block(params) - - self.assertEqual(genesis.ident,name) - self.assertEqual(genesis.discoTimestamp,t) - self.assertEqual(genesis.arrivTimestamp,s) - self.assertTrue(genesis.parent is None) - self.assertEqual(genesis.diff,diff) - - bill.addBlock(genesis, mode, tr) - - self.assertTrue(genesis.ident in bill.blocks) - self.assertTrue(genesis.ident in bill.leaves) - self.assertEqual(len(bill.miningIdents),1) - self.assertEqual(genesis.ident, bill.miningIdents[0]) - self.assertEqual(bill.diff, 1.0) - - parent = genesis.ident - oldDiff = bill.diff - i = 1 - - while len(bill.blocks)<2016*i-1: - newName = newIdent(len(bill.blocks)) - t += deltaT - s += deltaT - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - parent = newName - - # Just one more block and difficulty should recompute. - print("Just one more block and difficulty should recompute.") - self.assertEqual(bill.diff, oldDiff) - newName = newIdent(len(bill.blocks)) - t += deltaT - s += deltaT - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - parent = newName - self.assertEqual(bill.diff, oldDiff) - - oldDiff = bill.diff - i += 1 - - while len(bill.blocks)<2016*i-1: - newName = newIdent(len(bill.blocks)) - t += deltaT - s += deltaT - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - parent = newName - - # Just one more block and difficulty should recompute. - print("Just one more block and difficulty should again recompute.") - self.assertEqual(bill.diff, oldDiff) - newName = newIdent(len(bill.blocks)) - t += deltaT - s += deltaT - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - parent = newName - self.assertEqual(bill.diff, oldDiff) - - oldDiff = bill.diff - i += 1 - a = 1.1 - b = 1.0/a - - # If blocks arrive slightly further apart, difficulty should drop. - while len(bill.blocks)<2016*i-1: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - parent = newName - - print("Just one more block and difficulty will go down.") - - self.assertEqual(bill.diff, oldDiff) - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - parent = newName - err = abs(bill.diff - oldDiff*b) - self.assertTrue(err*err < 10**-15) - oldDiff = bill.diff - i += 1 - - - # If blocks then arrive on target, difficulty should freeze. - a = 1.0 - b = 1.0/a - while len(bill.blocks)<2016*i-1: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - parent = newName - - self.assertEqual(bill.diff, oldDiff) - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - parent = newName - self.assertEqual(bill.diff, oldDiff) - oldDiff = bill.diff - i += 1 - - # If blocks arrive too close together, difficulty should increase. - a = 0.9 - b = 1.0/a - while len(bill.blocks)<2016*i-1: - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - - bill.addBlock(newBlock, mode, tr) - parent = newName - - print("Just one more block and difficulty should go up.") - self.assertEqual(bill.diff, oldDiff) - newName = newIdent(len(bill.blocks)) - t += deltaT*a - s += deltaT*a - diff = bill.diff - params = {"ident":newName, "disco":t, "arriv":s, "parent":parent, "diff":diff} - newBlock = Block(params) - bill.addBlock(newBlock, mode, tr) - parent = newName - err = abs(bill.diff - oldDiff*b) - self.assertTrue(err*err < 10**-15) - ''' - - - - -suite = unittest.TestLoader().loadTestsFromTestCase(Test_Blockchain) -unittest.TextTestRunner(verbosity=1).run(suite) diff --git a/source-code/Poisson-Graphs/new/Node.py b/source-code/Poisson-Graphs/new/Node.py deleted file mode 100644 index 716fe4f..0000000 --- a/source-code/Poisson-Graphs/new/Node.py +++ /dev/null @@ -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) - diff --git a/source-code/Poisson-Graphs/new/Node.py~ b/source-code/Poisson-Graphs/new/Node.py~ deleted file mode 100644 index 716fe4f..0000000 --- a/source-code/Poisson-Graphs/new/Node.py~ +++ /dev/null @@ -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) - diff --git a/source-code/Poisson-Graphs/new/__pycache__/Block.cpython-35.pyc b/source-code/Poisson-Graphs/new/__pycache__/Block.cpython-35.pyc deleted file mode 100644 index 62b87dd..0000000 Binary files a/source-code/Poisson-Graphs/new/__pycache__/Block.cpython-35.pyc and /dev/null differ diff --git a/source-code/Poisson-Graphs/new/__pycache__/Blockchain.cpython-35.pyc b/source-code/Poisson-Graphs/new/__pycache__/Blockchain.cpython-35.pyc deleted file mode 100644 index 9602d14..0000000 Binary files a/source-code/Poisson-Graphs/new/__pycache__/Blockchain.cpython-35.pyc and /dev/null differ diff --git a/source-code/Poisson-Graphs/new/output.txt b/source-code/Poisson-Graphs/new/output.txt deleted file mode 100644 index 776c5db..0000000 --- a/source-code/Poisson-Graphs/new/output.txt +++ /dev/null @@ -1,2501 +0,0 @@ -time,rateConstant,difficulty,ratio -0.0,1.0,1.0,1.0 -60000.0,1.0,1.0,1.0 -120000.0,1.0,1.0,1.0 -180000.0,1.0,1.0,1.0 -240000.0,1.0,1.0,1.0 -300000.0,1.0,1.0,1.0 -360000.0,1.0,1.0,1.0 -420000.0,1.0,1.0,1.0 -480000.0,1.0,1.0,1.0 -540000.0,1.0,1.0,1.0 -600000.0,1.0,1.0,1.0 -660000.0,1.0,1.0,1.0 -720000.0,1.0,1.0,1.0 -780000.0,1.0,1.0,1.0 -840000.0,1.0,1.0,1.0 -900000.0,1.0,1.0,1.0 -960000.0,1.0,1.0,1.0 -1020000.0,1.0,1.0,1.0 -1080000.0,1.0,1.0,1.0 -1140000.0,1.0,1.0,1.0 -1200000.0,1.0,1.0,1.0 -1260000.0,1.0,1.0,1.0 -1320000.0,1.0,1.0,1.0 -1380000.0,1.0,1.0,1.0 -1440000.0,1.0,1.0,1.0 -1500000.0,1.0,1.0,1.0 -1560000.0,1.0,1.0,1.0 -1620000.0,1.0,1.0,1.0 -1680000.0,1.0,1.0,1.0 -1740000.0,1.0,1.0,1.0 -1800000.0,1.0,1.0,1.0 -1860000.0,1.0,1.0,1.0 -1920000.0,1.0,1.0,1.0 -1980000.0,1.0,1.0,1.0 -2040000.0,1.0,1.0,1.0 -2100000.0,1.0,1.0,1.0 -2160000.0,1.0,1.0,1.0 -2220000.0,1.0,1.0,1.0 -2280000.0,1.0,1.0,1.0 -2340000.0,1.0,1.0,1.0 -2400000.0,1.0,1.0,1.0 -2460000.0,1.0,1.0,1.0 -2520000.0,1.0,1.0,1.0 -2580000.0,1.0,1.0,1.0 -2640000.0,1.0,1.0,1.0 -2700000.0,1.0,1.0,1.0 -2760000.0,1.0,1.0,1.0 -2820000.0,1.0,1.0,1.0 -2880000.0,1.0,1.0,1.0 -2940000.0,1.0,1.0,1.0 -3000000.0,1.0,1.0,1.0 -3060000.0,1.0,1.0,1.0 -3120000.0,1.0,1.0,1.0 -3180000.0,1.0,1.0,1.0 -3240000.0,1.0,1.0,1.0 -3300000.0,1.0,1.0,1.0 -3360000.0,1.0,1.0,1.0 -3420000.0,1.0,1.0,1.0 -3480000.0,1.0,1.0,1.0 -3540000.0,1.0,1.0,1.0 -3600000.0,1.0,1.0,1.0 -3660000.0,1.0,1.0,1.0 -3720000.0,1.0,1.0,1.0 -3780000.0,1.0,1.0,1.0 -3840000.0,1.0,1.0,1.0 -3900000.0,1.0,1.0,1.0 -3960000.0,1.0,1.0,1.0 -4020000.0,1.0,1.0,1.0 -4080000.0,1.0,1.0,1.0 -4140000.0,1.0,1.0,1.0 -4200000.0,1.0,1.0,1.0 -4260000.0,1.0,1.0,1.0 -4320000.0,1.0,1.0,1.0 -4380000.0,1.0,1.0,1.0 -4440000.0,1.0,1.0,1.0 -4500000.0,1.0,1.0,1.0 -4560000.0,1.0,1.0,1.0 -4620000.0,1.0,1.0,1.0 -4680000.0,1.0,1.0,1.0 -4740000.0,1.0,1.0,1.0 -4800000.0,1.0,1.0,1.0 -4860000.0,1.0,1.0,1.0 -4920000.0,1.0,1.0,1.0 -4980000.0,1.0,1.0,1.0 -5040000.0,1.0,1.0,1.0 -5100000.0,1.0,1.0,1.0 -5160000.0,1.0,1.0,1.0 -5220000.0,1.0,1.0,1.0 -5280000.0,1.0,1.0,1.0 -5340000.0,1.0,1.0,1.0 -5400000.0,1.0,1.0,1.0 -5460000.0,1.0,1.0,1.0 -5520000.0,1.0,1.0,1.0 -5580000.0,1.0,1.0,1.0 -5640000.0,1.0,1.0,1.0 -5700000.0,1.0,1.0,1.0 -5760000.0,1.0,1.0,1.0 -5820000.0,1.0,1.0,1.0 -5880000.0,1.0,1.0,1.0 -5940000.0,1.0,1.0,1.0 -6000000.0,1.0,1.0,1.0 -6060000.0,1.0,1.0,1.0 -6120000.0,1.0,1.0,1.0 -6180000.0,1.0,1.0,1.0 -6240000.0,1.0,1.0,1.0 -6300000.0,1.0,1.0,1.0 -6360000.0,1.0,1.0,1.0 -6420000.0,1.0,1.0,1.0 -6480000.0,1.0,1.0,1.0 -6540000.0,1.0,1.0,1.0 -6600000.0,1.0,1.0,1.0 -6660000.0,1.0,1.0,1.0 -6720000.0,1.0,1.0,1.0 -6780000.0,1.0,1.0,1.0 -6840000.0,1.0,1.0,1.0 -6900000.0,1.0,1.0,1.0 -6960000.0,1.0,1.0,1.0 -7020000.0,1.0,1.0,1.0 -7080000.0,1.0,1.0,1.0 -7140000.0,1.0,1.0,1.0 -7200000.0,1.0,1.0,1.0 -7260000.0,1.0,1.0,1.0 -7320000.0,1.0,1.0,1.0 -7380000.0,1.0,1.0,1.0 -7440000.0,1.0,1.0,1.0 -7500000.0,1.0,1.0,1.0 -7560000.0,1.0,1.0,1.0 -7620000.0,1.0,1.0,1.0 -7680000.0,1.0,1.0,1.0 -7740000.0,1.0,1.0,1.0 -7800000.0,1.0,1.0,1.0 -7860000.0,1.0,1.0,1.0 -7920000.0,1.0,1.0,1.0 -7980000.0,1.0,1.0,1.0 -8040000.0,1.0,1.0,1.0 -8100000.0,1.0,1.0,1.0 -8160000.0,1.0,1.0,1.0 -8220000.0,1.0,1.0,1.0 -8280000.0,1.0,1.0,1.0 -8340000.0,1.0,1.0,1.0 -8400000.0,1.0,1.0,1.0 -8460000.0,1.0,1.0,1.0 -8520000.0,1.0,1.0,1.0 -8580000.0,1.0,1.0,1.0 -8640000.0,1.0,1.0,1.0 -8700000.0,1.0,1.0,1.0 -8760000.0,1.0,1.0,1.0 -8820000.0,1.0,1.0,1.0 -8880000.0,1.0,1.0,1.0 -8940000.0,1.0,1.0,1.0 -9000000.0,1.0,1.0,1.0 -9060000.0,1.0,1.0,1.0 -9120000.0,1.0,1.0,1.0 -9180000.0,1.0,1.0,1.0 -9240000.0,1.0,1.0,1.0 -9300000.0,1.0,1.0,1.0 -9360000.0,1.0,1.0,1.0 -9420000.0,1.0,1.0,1.0 -9480000.0,1.0,1.0,1.0 -9540000.0,1.0,1.0,1.0 -9600000.0,1.0,1.0,1.0 -9660000.0,1.0,1.0,1.0 -9720000.0,1.0,1.0,1.0 -9780000.0,1.0,1.0,1.0 -9840000.0,1.0,1.0,1.0 -9900000.0,1.0,1.0,1.0 -9960000.0,1.0,1.0,1.0 -10020000.0,1.0,1.0,1.0 -10080000.0,1.0,1.0,1.0 -10140000.0,1.0,1.0,1.0 -10200000.0,1.0,1.0,1.0 -10260000.0,1.0,1.0,1.0 -10320000.0,1.0,1.0,1.0 -10380000.0,1.0,1.0,1.0 -10440000.0,1.0,1.0,1.0 -10500000.0,1.0,1.0,1.0 -10560000.0,1.0,1.0,1.0 -10620000.0,1.0,1.0,1.0 -10680000.0,1.0,1.0,1.0 -10740000.0,1.0,1.0,1.0 -10800000.0,1.0,1.0,1.0 -10860000.0,1.0,1.0,1.0 -10920000.0,1.0,1.0,1.0 -10980000.0,1.0,1.0,1.0 -11040000.0,1.0,1.0,1.0 -11100000.0,1.0,1.0,1.0 -11160000.0,1.0,1.0,1.0 -11220000.0,1.0,1.0,1.0 -11280000.0,1.0,1.0,1.0 -11340000.0,1.0,1.0,1.0 -11400000.0,1.0,1.0,1.0 -11460000.0,1.0,1.0,1.0 -11520000.0,1.0,1.0,1.0 -11580000.0,1.0,1.0,1.0 -11640000.0,1.0,1.0,1.0 -11700000.0,1.0,1.0,1.0 -11760000.0,1.0,1.0,1.0 -11820000.0,1.0,1.0,1.0 -11880000.0,1.0,1.0,1.0 -11940000.0,1.0,1.0,1.0 -12000000.0,1.0,1.0,1.0 -12060000.0,1.0,1.0,1.0 -12120000.0,1.0,1.0,1.0 -12180000.0,1.0,1.0,1.0 -12240000.0,1.0,1.0,1.0 -12300000.0,1.0,1.0,1.0 -12360000.0,1.0,1.0,1.0 -12420000.0,1.0,1.0,1.0 -12480000.0,1.0,1.0,1.0 -12540000.0,1.0,1.0,1.0 -12600000.0,1.0,1.0,1.0 -12660000.0,1.0,1.0,1.0 -12720000.0,1.0,1.0,1.0 -12780000.0,1.0,1.0,1.0 -12840000.0,1.0,1.0,1.0 -12900000.0,1.0,1.0,1.0 -12960000.0,1.0,1.0,1.0 -13020000.0,1.0,1.0,1.0 -13080000.0,1.0,1.0,1.0 -13140000.0,1.0,1.0,1.0 -13200000.0,1.0,1.0,1.0 -13260000.0,1.0,1.0,1.0 -13320000.0,1.0,1.0,1.0 -13380000.0,1.0,1.0,1.0 -13440000.0,1.0,1.0,1.0 -13500000.0,1.0,1.0,1.0 -13560000.0,1.0,1.0,1.0 -13620000.0,1.0,1.0,1.0 -13680000.0,1.0,1.0,1.0 -13740000.0,1.0,1.0,1.0 -13800000.0,1.0,1.0,1.0 -13860000.0,1.0,1.0,1.0 -13920000.0,1.0,1.0,1.0 -13980000.0,1.0,1.0,1.0 -14040000.0,1.0,1.0,1.0 -14100000.0,1.0,1.0,1.0 -14160000.0,1.0,1.0,1.0 -14220000.0,1.0,1.0,1.0 -14280000.0,1.0,1.0,1.0 -14340000.0,1.0,1.0,1.0 -14400000.0,1.0,1.0,1.0 -14460000.0,1.0,1.0,1.0 -14520000.0,1.0,1.0,1.0 -14580000.0,1.0,1.0,1.0 -14640000.0,1.0,1.0,1.0 -14700000.0,1.0,1.0,1.0 -14760000.0,1.0,1.0,1.0 -14820000.0,1.0,1.0,1.0 -14880000.0,1.0,1.0,1.0 -14940000.0,1.0,1.0,1.0 -15000000.0,1.0,1.0,1.0 -15060000.0,1.0,1.0,1.0 -15120000.0,1.0,1.0,1.0 -15180000.0,1.0,1.0,1.0 -15240000.0,1.0,1.0,1.0 -15300000.0,1.0,1.0,1.0 -15360000.0,1.0,1.0,1.0 -15420000.0,1.0,1.0,1.0 -15480000.0,1.0,1.0,1.0 -15540000.0,1.0,1.0,1.0 -15600000.0,1.0,1.0,1.0 -15660000.0,1.0,1.0,1.0 -15720000.0,1.0,1.0,1.0 -15780000.0,1.0,1.0,1.0 -15840000.0,1.0,1.0,1.0 -15900000.0,1.0,1.0,1.0 -15960000.0,1.0,1.0,1.0 -16020000.0,1.0,1.0,1.0 -16080000.0,1.0,1.0,1.0 -16140000.0,1.0,1.0,1.0 -16200000.0,1.0,1.0,1.0 -16260000.0,1.0,1.0,1.0 -16320000.0,1.0,1.0,1.0 -16380000.0,1.0,1.0,1.0 -16440000.0,1.0,1.0,1.0 -16500000.0,1.0,1.0,1.0 -16560000.0,1.0,1.0,1.0 -16620000.0,1.0,1.0,1.0 -16680000.0,1.0,1.0,1.0 -16740000.0,1.0,1.0,1.0 -16800000.0,1.0,1.0,1.0 -16860000.0,1.0,1.0,1.0 -16920000.0,1.0,1.0,1.0 -16980000.0,1.0,1.0,1.0 -17040000.0,1.0,1.0,1.0 -17100000.0,1.0,1.0,1.0 -17160000.0,1.0,1.0,1.0 -17220000.0,1.0,1.0,1.0 -17280000.0,1.0,1.0,1.0 -17340000.0,1.0,1.0,1.0 -17400000.0,1.0,1.0,1.0 -17460000.0,1.0,1.0,1.0 -17520000.0,1.0,1.0,1.0 -17580000.0,1.0,1.0,1.0 -17640000.0,1.0,1.0,1.0 -17700000.0,1.0,1.0,1.0 -17760000.0,1.0,1.0,1.0 -17820000.0,1.0,1.0,1.0 -17880000.0,1.0,1.0,1.0 -17940000.0,1.0,1.0,1.0 -18000000.0,1.0,1.0,1.0 -18060000.0,1.0,1.0,1.0 -18120000.0,1.0,1.0,1.0 -18180000.0,1.0,1.0,1.0 -18240000.0,1.0,1.0,1.0 -18300000.0,1.0,1.0,1.0 -18360000.0,1.0,1.0,1.0 -18420000.0,1.0,1.0,1.0 -18480000.0,1.0,1.0,1.0 -18540000.0,1.0,1.0,1.0 -18600000.0,1.0,1.0,1.0 -18660000.0,1.0,1.0,1.0 -18720000.0,1.0,1.0,1.0 -18780000.0,1.0,1.0,1.0 -18840000.0,1.0,1.0,1.0 -18900000.0,1.0,1.0,1.0 -18960000.0,1.0,1.0,1.0 -19020000.0,1.0,1.0,1.0 -19080000.0,1.0,1.0,1.0 -19140000.0,1.0,1.0,1.0 -19200000.0,1.0,1.0,1.0 -19260000.0,1.0,1.0,1.0 -19320000.0,1.0,1.0,1.0 -19380000.0,1.0,1.0,1.0 -19440000.0,1.0,1.0,1.0 -19500000.0,1.0,1.0,1.0 -19560000.0,1.0,1.0,1.0 -19620000.0,1.0,1.0,1.0 -19680000.0,1.0,1.0,1.0 -19740000.0,1.0,1.0,1.0 -19800000.0,1.0,1.0,1.0 -19860000.0,1.0,1.0,1.0 -19920000.0,1.0,1.0,1.0 -19980000.0,1.0,1.0,1.0 -20040000.0,1.0,1.0,1.0 -20100000.0,1.0,1.0,1.0 -20160000.0,1.0,1.0,1.0 -20220000.0,1.0,1.0,1.0 -20280000.0,1.0,1.0,1.0 -20340000.0,1.0,1.0,1.0 -20400000.0,1.0,1.0,1.0 -20460000.0,1.0,1.0,1.0 -20520000.0,1.0,1.0,1.0 -20580000.0,1.0,1.0,1.0 -20640000.0,1.0,1.0,1.0 -20700000.0,1.0,1.0,1.0 -20760000.0,1.0,1.0,1.0 -20820000.0,1.0,1.0,1.0 -20880000.0,1.0,1.0,1.0 -20940000.0,1.0,1.0,1.0 -21000000.0,1.0,1.0,1.0 -21060000.0,1.0,1.0,1.0 -21120000.0,1.0,1.0,1.0 -21180000.0,1.0,1.0,1.0 -21240000.0,1.0,1.0,1.0 -21300000.0,1.0,1.0,1.0 -21360000.0,1.0,1.0,1.0 -21420000.0,1.0,1.0,1.0 -21480000.0,1.0,1.0,1.0 -21540000.0,1.0,1.0,1.0 -21600000.0,1.0,1.0,1.0 -21660000.0,1.0,1.0,1.0 -21720000.0,1.0,1.0,1.0 -21780000.0,1.0,1.0,1.0 -21840000.0,1.0,1.0,1.0 -21900000.0,1.0,1.0,1.0 -21960000.0,1.0,1.0,1.0 -22020000.0,1.0,1.0,1.0 -22080000.0,1.0,1.0,1.0 -22140000.0,1.0,1.0,1.0 -22200000.0,1.0,1.0,1.0 -22260000.0,1.0,1.0,1.0 -22320000.0,1.0,1.0,1.0 -22380000.0,1.0,1.0,1.0 -22440000.0,1.0,1.0,1.0 -22500000.0,1.0,1.0,1.0 -22560000.0,1.0,1.0,1.0 -22620000.0,1.0,1.0,1.0 -22680000.0,1.0,1.0,1.0 -22740000.0,1.0,1.0,1.0 -22800000.0,1.0,1.0,1.0 -22860000.0,1.0,1.0,1.0 -22920000.0,1.0,1.0,1.0 -22980000.0,1.0,1.0,1.0 -23040000.0,1.0,1.0,1.0 -23100000.0,1.0,1.0,1.0 -23160000.0,1.0,1.0,1.0 -23220000.0,1.0,1.0,1.0 -23280000.0,1.0,1.0,1.0 -23340000.0,1.0,1.0,1.0 -23400000.0,1.0,1.0,1.0 -23460000.0,1.0,1.0,1.0 -23520000.0,1.0,1.0,1.0 -23580000.0,1.0,1.0,1.0 -23640000.0,1.0,1.0,1.0 -23700000.0,1.0,1.0,1.0 -23760000.0,1.0,1.0,1.0 -23820000.0,1.0,1.0,1.0 -23880000.0,1.0,1.0,1.0 -23940000.0,1.0,1.0,1.0 -24000000.0,1.0,1.0,1.0 -24060000.0,1.0,1.0,1.0 -24120000.0,1.0,1.0,1.0 -24180000.0,1.0,1.0,1.0 -24240000.0,1.0,1.0,1.0 -24300000.0,1.0,1.0,1.0 -24360000.0,1.0,1.0,1.0 -24420000.0,1.0,1.0,1.0 -24480000.0,1.0,1.0,1.0 -24540000.0,1.0,1.0,1.0 -24600000.0,1.0,1.0,1.0 -24660000.0,1.0,1.0,1.0 -24720000.0,1.0,1.0,1.0 -24780000.0,1.0,1.0,1.0 -24840000.0,1.0,1.0,1.0 -24900000.0,1.0,1.0,1.0 -24960000.0,1.0,1.0,1.0 -25020000.0,1.0,1.0,1.0 -25080000.0,1.0,1.0,1.0 -25140000.0,1.0,1.0,1.0 -25200000.0,1.0,1.0,1.0 -25260000.0,1.0,1.0,1.0 -25320000.0,1.0,1.0,1.0 -25380000.0,1.0,1.0,1.0 -25440000.0,1.0,1.0,1.0 -25500000.0,1.0,1.0,1.0 -25560000.0,1.0,1.0,1.0 -25620000.0,1.0,1.0,1.0 -25680000.0,1.0,1.0,1.0 -25740000.0,1.0,1.0,1.0 -25800000.0,1.0,1.0,1.0 -25860000.0,1.0,1.0,1.0 -25920000.0,1.0,1.0,1.0 -25980000.0,1.0,1.0,1.0 -26040000.0,1.0,1.0,1.0 -26100000.0,1.0,1.0,1.0 -26160000.0,1.0,1.0,1.0 -26220000.0,1.0,1.0,1.0 -26280000.0,1.0,1.0,1.0 -26340000.0,1.0,1.0,1.0 -26400000.0,1.0,1.0,1.0 -26460000.0,1.0,1.0,1.0 -26520000.0,1.0,1.0,1.0 -26580000.0,1.0,1.0,1.0 -26640000.0,1.0,1.0,1.0 -26700000.0,1.0,1.0,1.0 -26760000.0,1.0,1.0,1.0 -26820000.0,1.0,1.0,1.0 -26880000.0,1.0,1.0,1.0 -26940000.0,1.0,1.0,1.0 -27000000.0,1.0,1.0,1.0 -27060000.0,1.0,1.0,1.0 -27120000.0,1.0,1.0,1.0 -27180000.0,1.0,1.0,1.0 -27240000.0,1.0,1.0,1.0 -27300000.0,1.0,1.0,1.0 -27360000.0,1.0,1.0,1.0 -27420000.0,1.0,1.0,1.0 -27480000.0,1.0,1.0,1.0 -27540000.0,1.0,1.0,1.0 -27600000.0,1.0,1.0,1.0 -27660000.0,1.0,1.0,1.0 -27720000.0,1.0,1.0,1.0 -27780000.0,1.0,1.0,1.0 -27840000.0,1.0,1.0,1.0 -27900000.0,1.0,1.0,1.0 -27960000.0,1.0,1.0,1.0 -28020000.0,1.0,1.0,1.0 -28080000.0,1.0,1.0,1.0 -28140000.0,1.0,1.0,1.0 -28200000.0,1.0,1.0,1.0 -28260000.0,1.0,1.0,1.0 -28320000.0,1.0,1.0,1.0 -28380000.0,1.0,1.0,1.0 -28440000.0,1.0,1.0,1.0 -28500000.0,1.0,1.0,1.0 -28560000.0,1.0,1.0,1.0 -28620000.0,1.0,1.0,1.0 -28680000.0,1.0,1.0,1.0 -28740000.0,1.0,1.0,1.0 -28800000.0,1.0,1.0,1.0 -28860000.0,1.0,1.0,1.0 -28920000.0,1.0,1.0,1.0 -28980000.0,1.0,1.0,1.0 -29040000.0,1.0,1.0,1.0 -29100000.0,1.0,1.0,1.0 -29160000.0,1.0,1.0,1.0 -29220000.0,1.0,1.0,1.0 -29280000.0,1.0,1.0,1.0 -29340000.0,1.0,1.0,1.0 -29400000.0,1.0,1.0,1.0 -29460000.0,1.0,1.0,1.0 -29520000.0,1.0,1.0,1.0 -29580000.0,1.0,1.0,1.0 -29640000.0,1.0,1.0,1.0 -29700000.0,1.0,1.0,1.0 -29760000.0,1.0,1.0,1.0 -29820000.0,1.0,1.0,1.0 -29880000.0,1.0,1.0,1.0 -29940000.0,1.0,1.0,1.0 -30000000.0,1.0,1.0,1.0 -30060000.0,1.0,1.0,1.0 -30120000.0,1.0,1.0,1.0 -30180000.0,1.0,1.0,1.0 -30240000.0,1.0,1.0,1.0 -30300000.0,1.0,1.0,1.0 -30360000.0,1.0,1.0,1.0 -30420000.0,1.0,1.0,1.0 -30480000.0,1.0,1.0,1.0 -30540000.0,1.0,1.0,1.0 -30600000.0,1.0,1.0,1.0 -30660000.0,1.0,1.0,1.0 -30720000.0,1.0,1.0,1.0 -30780000.0,1.0,1.0,1.0 -30840000.0,1.0,1.0,1.0 -30900000.0,1.0,1.0,1.0 -30960000.0,1.0,1.0,1.0 -31020000.0,1.0,1.0,1.0 -31080000.0,1.0,1.0,1.0 -31140000.0,1.0,1.0,1.0 -31200000.0,1.0,1.0,1.0 -31260000.0,1.0,1.0,1.0 -31320000.0,1.0,1.0,1.0 -31380000.0,1.0,1.0,1.0 -31440000.0,1.0,1.0,1.0 -31500000.0,1.0,1.0,1.0 -31560000.0,1.0,1.0,1.0 -31620000.0,1.0,1.0,1.0 -31680000.0,1.0,1.0,1.0 -31740000.0,1.0,1.0,1.0 -31800000.0,1.0,1.0,1.0 -31860000.0,1.0,1.0,1.0 -31920000.0,1.0,1.0,1.0 -31980000.0,1.0,1.0,1.0 -32040000.0,1.0,1.0,1.0 -32100000.0,1.0,1.0,1.0 -32160000.0,1.0,1.0,1.0 -32220000.0,1.0,1.0,1.0 -32280000.0,1.0,1.0,1.0 -32340000.0,1.0,1.0,1.0 -32400000.0,1.0,1.0,1.0 -32460000.0,1.0,1.0,1.0 -32520000.0,1.0,1.0,1.0 -32580000.0,1.0,1.0,1.0 -32640000.0,1.0,1.0,1.0 -32700000.0,1.0,1.0,1.0 -32760000.0,1.0,1.0,1.0 -32820000.0,1.0,1.0,1.0 -32880000.0,1.0,1.0,1.0 -32940000.0,1.0,1.0,1.0 -33000000.0,1.0,1.0,1.0 -33060000.0,1.0,1.0,1.0 -33120000.0,1.0,1.0,1.0 -33180000.0,1.0,1.0,1.0 -33240000.0,1.0,1.0,1.0 -33300000.0,1.0,1.0,1.0 -33360000.0,1.0,1.0,1.0 -33420000.0,1.0,1.0,1.0 -33480000.0,1.0,1.0,1.0 -33540000.0,1.0,1.0,1.0 -33600000.0,1.0,1.0,1.0 -33660000.0,1.0,1.0,1.0 -33720000.0,1.0,1.0,1.0 -33780000.0,1.0,1.0,1.0 -33840000.0,1.0,1.0,1.0 -33900000.0,1.0,1.0,1.0 -33960000.0,1.0,1.0,1.0 -34020000.0,1.0,1.0,1.0 -34080000.0,1.0,1.0,1.0 -34140000.0,1.0,1.0,1.0 -34200000.0,1.0,1.0,1.0 -34260000.0,1.0,1.0,1.0 -34320000.0,1.0,1.0,1.0 -34380000.0,1.0,1.0,1.0 -34440000.0,1.0,1.0,1.0 -34500000.0,1.0,1.0,1.0 -34560000.0,1.0,1.0,1.0 -34620000.0,1.0,1.0,1.0 -34680000.0,1.0,1.0,1.0 -34740000.0,1.0,1.0,1.0 -34800000.0,1.0,1.0,1.0 -34860000.0,1.0,1.0,1.0 -34920000.0,1.0,1.0,1.0 -34980000.0,1.0,1.0,1.0 -35040000.0,1.0,1.0,1.0 -35100000.0,1.0,1.0,1.0 -35160000.0,1.0,1.0,1.0 -35220000.0,1.0,1.0,1.0 -35280000.0,1.0,1.0,1.0 -35340000.0,1.0,1.0,1.0 -35400000.0,1.0,1.0,1.0 -35460000.0,1.0,1.0,1.0 -35520000.0,1.0,1.0,1.0 -35580000.0,1.0,1.0,1.0 -35640000.0,1.0,1.0,1.0 -35700000.0,1.0,1.0,1.0 -35760000.0,1.0,1.0,1.0 -35820000.0,1.0,1.0,1.0 -35880000.0,1.0,1.0,1.0 -35940000.0,1.0,1.0,1.0 -36000000.0,1.0,1.0,1.0 -36060000.0,1.0,1.0,1.0 -36120000.0,1.0,1.0,1.0 -36180000.0,1.0,1.0,1.0 -36240000.0,1.0,1.0,1.0 -36300000.0,1.0,1.0,1.0 -36360000.0,1.0,1.0,1.0 -36420000.0,1.0,1.0,1.0 -36480000.0,1.0,1.0,1.0 -36540000.0,1.0,1.0,1.0 -36600000.0,1.0,1.0,1.0 -36660000.0,1.0,1.0,1.0 -36720000.0,1.0,1.0,1.0 -36780000.0,1.0,1.0,1.0 -36840000.0,1.0,1.0,1.0 -36900000.0,1.0,1.0,1.0 -36960000.0,1.0,1.0,1.0 -37020000.0,1.0,1.0,1.0 -37080000.0,1.0,1.0,1.0 -37140000.0,1.0,1.0,1.0 -37200000.0,1.0,1.0,1.0 -37260000.0,1.0,1.0,1.0 -37320000.0,1.0,1.0,1.0 -37380000.0,1.0,1.0,1.0 -37440000.0,1.0,1.0,1.0 -37500000.0,1.0,1.0,1.0 -37560000.0,1.0,1.0,1.0 -37620000.0,1.0,1.0,1.0 -37680000.0,1.0,1.0,1.0 -37740000.0,1.0,1.0,1.0 -37800000.0,1.0,1.0,1.0 -37860000.0,1.0,1.0,1.0 -37920000.0,1.0,1.0,1.0 -37980000.0,1.0,1.0,1.0 -38040000.0,1.0,1.0,1.0 -38100000.0,1.0,1.0,1.0 -38160000.0,1.0,1.0,1.0 -38220000.0,1.0,1.0,1.0 -38280000.0,1.0,1.0,1.0 -38340000.0,1.0,1.0,1.0 -38400000.0,1.0,1.0,1.0 -38460000.0,1.0,1.0,1.0 -38520000.0,1.0,1.0,1.0 -38580000.0,1.0,1.0,1.0 -38640000.0,1.0,1.0,1.0 -38700000.0,1.0,1.0,1.0 -38760000.0,1.0,1.0,1.0 -38820000.0,1.0,1.0,1.0 -38880000.0,1.0,1.0,1.0 -38940000.0,1.0,1.0,1.0 -39000000.0,1.0,1.0,1.0 -39060000.0,1.0,1.0,1.0 -39120000.0,1.0,1.0,1.0 -39180000.0,1.0,1.0,1.0 -39240000.0,1.0,1.0,1.0 -39300000.0,1.0,1.0,1.0 -39360000.0,1.0,1.0,1.0 -39420000.0,1.0,1.0,1.0 -39480000.0,1.0,1.0,1.0 -39540000.0,1.0,1.0,1.0 -39600000.0,1.0,1.0,1.0 -39660000.0,1.0,1.0,1.0 -39720000.0,1.0,1.0,1.0 -39780000.0,1.0,1.0,1.0 -39840000.0,1.0,1.0,1.0 -39900000.0,1.0,1.0,1.0 -39960000.0,1.0,1.0,1.0 -40020000.0,1.0,1.0,1.0 -40080000.0,1.0,1.0,1.0 -40140000.0,1.0,1.0,1.0 -40200000.0,1.0,1.0,1.0 -40260000.0,1.0,1.0,1.0 -40320000.0,1.0,1.0,1.0 -40380000.0,1.0,1.0,1.0 -40440000.0,1.0,1.0,1.0 -40500000.0,1.0,1.0,1.0 -40560000.0,1.0,1.0,1.0 -40620000.0,1.0,1.0,1.0 -40680000.0,1.0,1.0,1.0 -40740000.0,1.0,1.0,1.0 -40800000.0,1.0,1.0,1.0 -40860000.0,1.0,1.0,1.0 -40920000.0,1.0,1.0,1.0 -40980000.0,1.0,1.0,1.0 -41040000.0,1.0,1.0,1.0 -41100000.0,1.0,1.0,1.0 -41160000.0,1.0,1.0,1.0 -41220000.0,1.0,1.0,1.0 -41280000.0,1.0,1.0,1.0 -41340000.0,1.0,1.0,1.0 -41400000.0,1.0,1.0,1.0 -41460000.0,1.0,1.0,1.0 -41520000.0,1.0,1.0,1.0 -41580000.0,1.0,1.0,1.0 -41640000.0,1.0,1.0,1.0 -41700000.0,1.0,1.0,1.0 -41760000.0,1.0,1.0,1.0 -41820000.0,1.0,1.0,1.0 -41880000.0,1.0,1.0,1.0 -41940000.0,1.0,1.0,1.0 -42000000.0,1.0,1.0,1.0 -42060000.0,1.0,1.0,1.0 -42120000.0,1.0,1.0,1.0 -42180000.0,1.0,1.0,1.0 -42240000.0,1.0,1.0,1.0 -42300000.0,1.0,1.0,1.0 -42360000.0,1.0,1.0,1.0 -42420000.0,1.0,1.0,1.0 -42480000.0,1.0,1.0,1.0 -42540000.0,1.0,1.0,1.0 -42600000.0,1.0,1.0,1.0 -42660000.0,1.0,1.0,1.0 -42720000.0,1.0,1.0,1.0 -42780000.0,1.0,1.0,1.0 -42840000.0,1.0,1.0,1.0 -42900000.0,1.0,1.0,1.0 -42960000.0,1.0,1.0,1.0 -43020000.0,1.0,1.0,1.0 -43080000.0,1.0,1.0,1.0 -43140000.0,1.0,1.0,1.0 -43200000.0,1.0,1.0,1.0 -43260000.0,1.0,1.0,1.0 -43320000.0,1.0,1.0,1.0 -43380000.0,1.0,1.0,1.0 -43440000.0,1.0,1.0,1.0 -43500000.0,1.0,1.0,1.0 -43560000.0,1.0,1.0,1.0 -43620000.0,1.0,1.0,1.0 -43680000.0,1.0,1.0,1.0 -43740000.0,1.0,1.0,1.0 -43800000.0,1.0,1.0,1.0 -43860000.0,1.0,1.0,1.0 -43920000.0,1.0,1.0,1.0 -43980000.0,1.0,1.0,1.0 -44040000.0,1.0,1.0,1.0 -44100000.0,1.0,1.0,1.0 -44160000.0,1.0,1.0,1.0 -44220000.0,1.0,1.0,1.0 -44280000.0,1.0,1.0,1.0 -44340000.0,1.0,1.0,1.0 -44400000.0,1.0,1.0,1.0 -44460000.0,1.0,1.0,1.0 -44520000.0,1.0,1.0,1.0 -44580000.0,1.0,1.0,1.0 -44640000.0,1.0,1.0,1.0 -44700000.0,1.0,1.0,1.0 -44760000.0,1.0,1.0,1.0 -44820000.0,1.0,1.0,1.0 -44880000.0,1.0,1.0,1.0 -44940000.0,1.0,1.0,1.0 -45000000.0,1.0,1.0,1.0 -45060000.0,1.0,1.0,1.0 -45120000.0,1.0,1.0,1.0 -45180000.0,1.0,1.0,1.0 -45240000.0,1.0,1.0,1.0 -45300000.0,1.0,1.0,1.0 -45360000.0,1.0,1.0,1.0 -45420000.0,1.0,1.0,1.0 -45480000.0,1.0,1.0,1.0 -45540000.0,1.0,1.0,1.0 -45600000.0,1.0,1.0,1.0 -45660000.0,1.0,1.0,1.0 -45720000.0,1.0,1.0,1.0 -45780000.0,1.0,1.0,1.0 -45840000.0,1.0,1.0,1.0 -45900000.0,1.0,1.0,1.0 -45960000.0,1.0,1.0,1.0 -46020000.0,1.0,1.0,1.0 -46080000.0,1.0,1.0,1.0 -46140000.0,1.0,1.0,1.0 -46200000.0,1.0,1.0,1.0 -46260000.0,1.0,1.0,1.0 -46320000.0,1.0,1.0,1.0 -46380000.0,1.0,1.0,1.0 -46440000.0,1.0,1.0,1.0 -46500000.0,1.0,1.0,1.0 -46560000.0,1.0,1.0,1.0 -46620000.0,1.0,1.0,1.0 -46680000.0,1.0,1.0,1.0 -46740000.0,1.0,1.0,1.0 -46800000.0,1.0,1.0,1.0 -46860000.0,1.0,1.0,1.0 -46920000.0,1.0,1.0,1.0 -46980000.0,1.0,1.0,1.0 -47040000.0,1.0,1.0,1.0 -47100000.0,1.0,1.0,1.0 -47160000.0,1.0,1.0,1.0 -47220000.0,1.0,1.0,1.0 -47280000.0,1.0,1.0,1.0 -47340000.0,1.0,1.0,1.0 -47400000.0,1.0,1.0,1.0 -47460000.0,1.0,1.0,1.0 -47520000.0,1.0,1.0,1.0 -47580000.0,1.0,1.0,1.0 -47640000.0,1.0,1.0,1.0 -47700000.0,1.0,1.0,1.0 -47760000.0,1.0,1.0,1.0 -47820000.0,1.0,1.0,1.0 -47880000.0,1.0,1.0,1.0 -47940000.0,1.0,1.0,1.0 -48000000.0,1.0,1.0,1.0 -48060000.0,1.0,1.0,1.0 -48120000.0,1.0,1.0,1.0 -48180000.0,1.0,1.0,1.0 -48240000.0,1.0,1.0,1.0 -48300000.0,1.0,1.0,1.0 -48360000.0,1.0,1.0,1.0 -48420000.0,1.0,1.0,1.0 -48480000.0,1.0,1.0,1.0 -48540000.0,1.0,1.0,1.0 -48600000.0,1.0,1.0,1.0 -48660000.0,1.0,1.0,1.0 -48720000.0,1.0,1.0,1.0 -48780000.0,1.0,1.0,1.0 -48840000.0,1.0,1.0,1.0 -48900000.0,1.0,1.0,1.0 -48960000.0,1.0,1.0,1.0 -49020000.0,1.0,1.0,1.0 -49080000.0,1.0,1.0,1.0 -49140000.0,1.0,1.0,1.0 -49200000.0,1.0,1.0,1.0 -49260000.0,1.0,1.0,1.0 -49320000.0,1.0,1.0,1.0 -49380000.0,1.0,1.0,1.0 -49440000.0,1.0,1.0,1.0 -49500000.0,1.0,1.0,1.0 -49560000.0,1.0,1.0,1.0 -49620000.0,1.0,1.0,1.0 -49680000.0,1.0,1.0,1.0 -49740000.0,1.0,1.0,1.0 -49800000.0,1.0,1.0,1.0 -49860000.0,1.0,1.0,1.0 -49920000.0,1.0,1.0,1.0 -49980000.0,1.0,1.0,1.0 -50040000.0,1.0,1.0,1.0 -50100000.0,1.0,1.0,1.0 -50160000.0,1.0,1.0,1.0 -50220000.0,1.0,1.0,1.0 -50280000.0,1.0,1.0,1.0 -50340000.0,1.0,1.0,1.0 -50400000.0,1.0,1.0,1.0 -50460000.0,1.0,1.0,1.0 -50520000.0,1.0,1.0,1.0 -50580000.0,1.0,1.0,1.0 -50640000.0,1.0,1.0,1.0 -50700000.0,1.0,1.0,1.0 -50760000.0,1.0,1.0,1.0 -50820000.0,1.0,1.0,1.0 -50880000.0,1.0,1.0,1.0 -50940000.0,1.0,1.0,1.0 -51000000.0,1.0,1.0,1.0 -51060000.0,1.0,1.0,1.0 -51120000.0,1.0,1.0,1.0 -51180000.0,1.0,1.0,1.0 -51240000.0,1.0,1.0,1.0 -51300000.0,1.0,1.0,1.0 -51360000.0,1.0,1.0,1.0 -51420000.0,1.0,1.0,1.0 -51480000.0,1.0,1.0,1.0 -51540000.0,1.0,1.0,1.0 -51600000.0,1.0,1.0,1.0 -51660000.0,1.0,1.0,1.0 -51720000.0,1.0,1.0,1.0 -51780000.0,1.0,1.0,1.0 -51840000.0,1.0,1.0,1.0 -51900000.0,1.0,1.0,1.0 -51960000.0,1.0,1.0,1.0 -52020000.0,1.0,1.0,1.0 -52080000.0,1.0,1.0,1.0 -52140000.0,1.0,1.0,1.0 -52200000.0,1.0,1.0,1.0 -52260000.0,1.0,1.0,1.0 -52320000.0,1.0,1.0,1.0 -52380000.0,1.0,1.0,1.0 -52440000.0,1.0,1.0,1.0 -52500000.0,1.0,1.0,1.0 -52560000.0,1.0,1.0,1.0 -52620000.0,1.0,1.0,1.0 -52680000.0,1.0,1.0,1.0 -52740000.0,1.0,1.0,1.0 -52800000.0,1.0,1.0,1.0 -52860000.0,1.0,1.0,1.0 -52920000.0,1.0,1.0,1.0 -52980000.0,1.0,1.0,1.0 -53040000.0,1.0,1.0,1.0 -53100000.0,1.0,1.0,1.0 -53160000.0,1.0,1.0,1.0 -53220000.0,1.0,1.0,1.0 -53280000.0,1.0,1.0,1.0 -53340000.0,1.0,1.0,1.0 -53400000.0,1.0,1.0,1.0 -53460000.0,1.0,1.0,1.0 -53520000.0,1.0,1.0,1.0 -53580000.0,1.0,1.0,1.0 -53640000.0,1.0,1.0,1.0 -53700000.0,1.0,1.0,1.0 -53760000.0,1.0,1.0,1.0 -53820000.0,1.0,1.0,1.0 -53880000.0,1.0,1.0,1.0 -53940000.0,1.0,1.0,1.0 -54000000.0,1.0,1.0,1.0 -54060000.0,1.0,1.0,1.0 -54120000.0,1.0,1.0,1.0 -54180000.0,1.0,1.0,1.0 -54240000.0,1.0,1.0,1.0 -54300000.0,1.0,1.0,1.0 -54360000.0,1.0,1.0,1.0 -54420000.0,1.0,1.0,1.0 -54480000.0,1.0,1.0,1.0 -54540000.0,1.0,1.0,1.0 -54600000.0,1.0,1.0,1.0 -54660000.0,1.0,1.0,1.0 -54720000.0,1.0,1.0,1.0 -54780000.0,1.0,1.0,1.0 -54840000.0,1.0,1.0,1.0 -54900000.0,1.0,1.0,1.0 -54960000.0,1.0,1.0,1.0 -55020000.0,1.0,1.0,1.0 -55080000.0,1.0,1.0,1.0 -55140000.0,1.0,1.0,1.0 -55200000.0,1.0,1.0,1.0 -55260000.0,1.0,1.0,1.0 -55320000.0,1.0,1.0,1.0 -55380000.0,1.0,1.0,1.0 -55440000.0,1.0,1.0,1.0 -55500000.0,1.0,1.0,1.0 -55560000.0,1.0,1.0,1.0 -55620000.0,1.0,1.0,1.0 -55680000.0,1.0,1.0,1.0 -55740000.0,1.0,1.0,1.0 -55800000.0,1.0,1.0,1.0 -55860000.0,1.0,1.0,1.0 -55920000.0,1.0,1.0,1.0 -55980000.0,1.0,1.0,1.0 -56040000.0,1.0,1.0,1.0 -56100000.0,1.0,1.0,1.0 -56160000.0,1.0,1.0,1.0 -56220000.0,1.0,1.0,1.0 -56280000.0,1.0,1.0,1.0 -56340000.0,1.0,1.0,1.0 -56400000.0,1.0,1.0,1.0 -56460000.0,1.0,1.0,1.0 -56520000.0,1.0,1.0,1.0 -56580000.0,1.0,1.0,1.0 -56640000.0,1.0,1.0,1.0 -56700000.0,1.0,1.0,1.0 -56760000.0,1.0,1.0,1.0 -56820000.0,1.0,1.0,1.0 -56880000.0,1.0,1.0,1.0 -56940000.0,1.0,1.0,1.0 -57000000.0,1.0,1.0,1.0 -57060000.0,1.0,1.0,1.0 -57120000.0,1.0,1.0,1.0 -57180000.0,1.0,1.0,1.0 -57240000.0,1.0,1.0,1.0 -57300000.0,1.0,1.0,1.0 -57360000.0,1.0,1.0,1.0 -57420000.0,1.0,1.0,1.0 -57480000.0,1.0,1.0,1.0 -57540000.0,1.0,1.0,1.0 -57600000.0,1.0,1.0,1.0 -57660000.0,1.0,1.0,1.0 -57720000.0,1.0,1.0,1.0 -57780000.0,1.0,1.0,1.0 -57840000.0,1.0,1.0,1.0 -57900000.0,1.0,1.0,1.0 -57960000.0,1.0,1.0,1.0 -58020000.0,1.0,1.0,1.0 -58080000.0,1.0,1.0,1.0 -58140000.0,1.0,1.0,1.0 -58200000.0,1.0,1.0,1.0 -58260000.0,1.0,1.0,1.0 -58320000.0,1.0,1.0,1.0 -58380000.0,1.0,1.0,1.0 -58440000.0,1.0,1.0,1.0 -58500000.0,1.0,1.0,1.0 -58560000.0,1.0,1.0,1.0 -58620000.0,1.0,1.0,1.0 -58680000.0,1.0,1.0,1.0 -58740000.0,1.0,1.0,1.0 -58800000.0,1.0,1.0,1.0 -58860000.0,1.0,1.0,1.0 -58920000.0,1.0,1.0,1.0 -58980000.0,1.0,1.0,1.0 -59040000.0,1.0,1.0,1.0 -59100000.0,1.0,1.0,1.0 -59160000.0,1.0,1.0,1.0 -59220000.0,1.0,1.0,1.0 -59280000.0,1.0,1.0,1.0 -59340000.0,1.0,1.0,1.0 -59400000.0,1.0,1.0,1.0 -59460000.0,1.0,1.0,1.0 -59520000.0,1.0,1.0,1.0 -59580000.0,1.0,1.0,1.0 -59640000.0,1.0,1.0,1.0 -59700000.0,1.0,1.0,1.0 -59760000.0,1.0,1.0,1.0 -59820000.0,1.0,1.0,1.0 -59880000.0,1.0,1.0,1.0 -59940000.0,1.0,1.0,1.0 -60000000.0,1.0,1.0,1.0 -60060000.0,1.0,1.0,1.0 -60120000.0,1.0,1.0,1.0 -60180000.0,1.0,1.0,1.0 -60240000.0,1.0,1.0,1.0 -60300000.0,1.0,1.0,1.0 -60360000.0,1.0,1.0,1.0 -60420000.0,1.0,1.0,1.0 -60480000.0,1.0,1.0,1.0 -60540000.0,1.0,1.0,1.0 -60600000.0,1.0,1.0,1.0 -60660000.0,1.0,1.0,1.0 -60720000.0,1.0,1.0,1.0 -60780000.0,1.0,1.0,1.0 -60840000.0,1.0,1.0,1.0 -60900000.0,1.0,1.0,1.0 -60960000.0,1.0,1.0,1.0 -61020000.0,1.0,1.0,1.0 -61080000.0,1.0,1.0,1.0 -61140000.0,1.0,1.0,1.0 -61200000.0,1.0,1.0,1.0 -61260000.0,1.0,1.0,1.0 -61320000.0,1.0,1.0,1.0 -61380000.0,1.0,1.0,1.0 -61440000.0,1.0,1.0,1.0 -61500000.0,1.0,1.0,1.0 -61560000.0,1.0,1.0,1.0 -61620000.0,1.0,1.0,1.0 -61680000.0,1.0,1.0,1.0 -61740000.0,1.0,1.0,1.0 -61800000.0,1.0,1.0,1.0 -61860000.0,1.0,1.0,1.0 -61920000.0,1.0,1.0,1.0 -61980000.0,1.0,1.0,1.0 -62040000.0,1.0,1.0,1.0 -62100000.0,1.0,1.0,1.0 -62160000.0,1.0,1.0,1.0 -62220000.0,1.0,1.0,1.0 -62280000.0,1.0,1.0,1.0 -62340000.0,1.0,1.0,1.0 -62400000.0,1.0,1.0,1.0 -62460000.0,1.0,1.0,1.0 -62520000.0,1.0,1.0,1.0 -62580000.0,1.0,1.0,1.0 -62640000.0,1.0,1.0,1.0 -62700000.0,1.0,1.0,1.0 -62760000.0,1.0,1.0,1.0 -62820000.0,1.0,1.0,1.0 -62880000.0,1.0,1.0,1.0 -62940000.0,1.0,1.0,1.0 -63000000.0,1.0,1.0,1.0 -63060000.0,1.0,1.0,1.0 -63120000.0,1.0,1.0,1.0 -63180000.0,1.0,1.0,1.0 -63240000.0,1.0,1.0,1.0 -63300000.0,1.0,1.0,1.0 -63360000.0,1.0,1.0,1.0 -63420000.0,1.0,1.0,1.0 -63480000.0,1.0,1.0,1.0 -63540000.0,1.0,1.0,1.0 -63600000.0,1.0,1.0,1.0 -63660000.0,1.0,1.0,1.0 -63720000.0,1.0,1.0,1.0 -63780000.0,1.0,1.0,1.0 -63840000.0,1.0,1.0,1.0 -63900000.0,1.0,1.0,1.0 -63960000.0,1.0,1.0,1.0 -64020000.0,1.0,1.0,1.0 -64080000.0,1.0,1.0,1.0 -64140000.0,1.0,1.0,1.0 -64200000.0,1.0,1.0,1.0 -64260000.0,1.0,1.0,1.0 -64320000.0,1.0,1.0,1.0 -64380000.0,1.0,1.0,1.0 -64440000.0,1.0,1.0,1.0 -64500000.0,1.0,1.0,1.0 -64560000.0,1.0,1.0,1.0 -64620000.0,1.0,1.0,1.0 -64680000.0,1.0,1.0,1.0 -64740000.0,1.0,1.0,1.0 -64800000.0,1.0,1.0,1.0 -64860000.0,1.0,1.0,1.0 -64920000.0,1.0,1.0,1.0 -64980000.0,1.0,1.0,1.0 -65040000.0,1.0,1.0,1.0 -65100000.0,1.0,1.0,1.0 -65160000.0,1.0,1.0,1.0 -65220000.0,1.0,1.0,1.0 -65280000.0,1.0,1.0,1.0 -65340000.0,1.0,1.0,1.0 -65400000.0,1.0,1.0,1.0 -65460000.0,1.0,1.0,1.0 -65520000.0,1.0,1.0,1.0 -65580000.0,1.0,1.0,1.0 -65640000.0,1.0,1.0,1.0 -65700000.0,1.0,1.0,1.0 -65760000.0,1.0,1.0,1.0 -65820000.0,1.0,1.0,1.0 -65880000.0,1.0,1.0,1.0 -65940000.0,1.0,1.0,1.0 -66000000.0,1.0,1.0,1.0 -66060000.0,1.0,1.0,1.0 -66120000.0,1.0,1.0,1.0 -66180000.0,1.0,1.0,1.0 -66240000.0,1.0,1.0,1.0 -66300000.0,1.0,1.0,1.0 -66360000.0,1.0,1.0,1.0 -66420000.0,1.0,1.0,1.0 -66480000.0,1.0,1.0,1.0 -66540000.0,1.0,1.0,1.0 -66600000.0,1.0,1.0,1.0 -66660000.0,1.0,1.0,1.0 -66720000.0,1.0,1.0,1.0 -66780000.0,1.0,1.0,1.0 -66840000.0,1.0,1.0,1.0 -66900000.0,1.0,1.0,1.0 -66960000.0,1.0,1.0,1.0 -67020000.0,1.0,1.0,1.0 -67080000.0,1.0,1.0,1.0 -67140000.0,1.0,1.0,1.0 -67200000.0,1.0,1.0,1.0 -67260000.0,1.0,1.0,1.0 -67320000.0,1.0,1.0,1.0 -67380000.0,1.0,1.0,1.0 -67440000.0,1.0,1.0,1.0 -67500000.0,1.0,1.0,1.0 -67560000.0,1.0,1.0,1.0 -67620000.0,1.0,1.0,1.0 -67680000.0,1.0,1.0,1.0 -67740000.0,1.0,1.0,1.0 -67800000.0,1.0,1.0,1.0 -67860000.0,1.0,1.0,1.0 -67920000.0,1.0,1.0,1.0 -67980000.0,1.0,1.0,1.0 -68040000.0,1.0,1.0,1.0 -68100000.0,1.0,1.0,1.0 -68160000.0,1.0,1.0,1.0 -68220000.0,1.0,1.0,1.0 -68280000.0,1.0,1.0,1.0 -68340000.0,1.0,1.0,1.0 -68400000.0,1.0,1.0,1.0 -68460000.0,1.0,1.0,1.0 -68520000.0,1.0,1.0,1.0 -68580000.0,1.0,1.0,1.0 -68640000.0,1.0,1.0,1.0 -68700000.0,1.0,1.0,1.0 -68760000.0,1.0,1.0,1.0 -68820000.0,1.0,1.0,1.0 -68880000.0,1.0,1.0,1.0 -68940000.0,1.0,1.0,1.0 -69000000.0,1.0,1.0,1.0 -69060000.0,1.0,1.0,1.0 -69120000.0,1.0,1.0,1.0 -69180000.0,1.0,1.0,1.0 -69240000.0,1.0,1.0,1.0 -69300000.0,1.0,1.0,1.0 -69360000.0,1.0,1.0,1.0 -69420000.0,1.0,1.0,1.0 -69480000.0,1.0,1.0,1.0 -69540000.0,1.0,1.0,1.0 -69600000.0,1.0,1.0,1.0 -69660000.0,1.0,1.0,1.0 -69720000.0,1.0,1.0,1.0 -69780000.0,1.0,1.0,1.0 -69840000.0,1.0,1.0,1.0 -69900000.0,1.0,1.0,1.0 -69960000.0,1.0,1.0,1.0 -70020000.0,1.0,1.0,1.0 -70080000.0,1.0,1.0,1.0 -70140000.0,1.0,1.0,1.0 -70200000.0,1.0,1.0,1.0 -70260000.0,1.0,1.0,1.0 -70320000.0,1.0,1.0,1.0 -70380000.0,1.0,1.0,1.0 -70440000.0,1.0,1.0,1.0 -70500000.0,1.0,1.0,1.0 -70560000.0,1.0,1.0,1.0 -70620000.0,1.0,1.0,1.0 -70680000.0,1.0,1.0,1.0 -70740000.0,1.0,1.0,1.0 -70800000.0,1.0,1.0,1.0 -70860000.0,1.0,1.0,1.0 -70920000.0,1.0,1.0,1.0 -70980000.0,1.0,1.0,1.0 -71040000.0,1.0,1.0,1.0 -71100000.0,1.0,1.0,1.0 -71160000.0,1.0,1.0,1.0 -71220000.0,1.0,1.0,1.0 -71280000.0,1.0,1.0,1.0 -71340000.0,1.0,1.0,1.0 -71400000.0,1.0,1.0,1.0 -71460000.0,1.0,1.0,1.0 -71520000.0,1.0,1.0,1.0 -71580000.0,1.0,1.0,1.0 -71640000.0,1.0,1.0,1.0 -71700000.0,1.0,1.0,1.0 -71760000.0,1.0,1.0,1.0 -71820000.0,1.0,1.0,1.0 -71880000.0,1.0,1.0,1.0 -71940000.0,1.0,1.0,1.0 -72006000.0,1.1,1.0,1.0 -72072000.0,1.1,1.0,1.0 -72138000.0,1.1,1.0,1.0 -72204000.0,1.1,1.0,1.0 -72270000.0,1.1,1.0,1.0 -72336000.0,1.1,1.0,1.0 -72402000.0,1.1,1.0,1.0 -72468000.0,1.1,1.0,1.0 -72534000.0,1.1,1.0,1.0 -72600000.0,1.1,1.0,1.0 -72666000.0,1.1,1.0,1.0 -72732000.0,1.1,1.0,1.0 -72798000.0,1.1,1.0,1.0 -72864000.0,1.1,1.0,1.0 -72930000.0,1.1,1.0,1.0 -72996000.0,1.1,1.0,1.0 -73062000.0,1.1,1.0,1.0 -73128000.0,1.1,1.0,1.0 -73194000.0,1.1,1.0,1.0 -73260000.0,1.1,1.0,1.0 -73326000.0,1.1,1.0,1.0 -73392000.0,1.1,1.0,1.0 -73458000.0,1.1,1.0,1.0 -73524000.0,1.1,1.0,1.0 -73590000.0,1.1,1.0,1.0 -73656000.0,1.1,1.0,1.0 -73722000.0,1.1,1.0,1.0 -73788000.0,1.1,1.0,1.0 -73854000.0,1.1,1.0,1.0 -73920000.0,1.1,1.0,1.0 -73986000.0,1.1,1.0,1.0 -74052000.0,1.1,1.0,1.0 -74118000.0,1.1,1.0,1.0 -74184000.0,1.1,1.0,1.0 -74250000.0,1.1,1.0,1.0 -74316000.0,1.1,1.0,1.0 -74382000.0,1.1,1.0,1.0 -74448000.0,1.1,1.0,1.0 -74514000.0,1.1,1.0,1.0 -74580000.0,1.1,1.0,1.0 -74646000.0,1.1,1.0,1.0 -74712000.0,1.1,1.0,1.0 -74778000.0,1.1,1.0,1.0 -74844000.0,1.1,1.0,1.0 -74910000.0,1.1,1.0,1.0 -74976000.0,1.1,1.0,1.0 -75042000.0,1.1,1.0,1.0 -75108000.0,1.1,1.0,1.0 -75174000.0,1.1,1.0,1.0 -75240000.0,1.1,1.0,1.0 -75306000.0,1.1,1.0,1.0 -75372000.0,1.1,1.0,1.0 -75438000.0,1.1,1.0,1.0 -75504000.0,1.1,1.0,1.0 -75570000.0,1.1,1.0,1.0 -75636000.0,1.1,1.0,1.0 -75702000.0,1.1,1.0,1.0 -75768000.0,1.1,1.0,1.0 -75834000.0,1.1,1.0,1.0 -75900000.0,1.1,1.0,1.0 -75966000.0,1.1,1.0,1.0 -76032000.0,1.1,1.0,1.0 -76098000.0,1.1,1.0,1.0 -76164000.0,1.1,1.0,1.0 -76230000.0,1.1,1.0,1.0 -76296000.0,1.1,1.0,1.0 -76362000.0,1.1,1.0,1.0 -76428000.0,1.1,1.0,1.0 -76494000.0,1.1,1.0,1.0 -76560000.0,1.1,1.0,1.0 -76626000.0,1.1,1.0,1.0 -76692000.0,1.1,1.0,1.0 -76758000.0,1.1,1.0,1.0 -76824000.0,1.1,1.0,1.0 -76890000.0,1.1,1.0,1.0 -76956000.0,1.1,1.0,1.0 -77022000.0,1.1,1.0,1.0 -77088000.0,1.1,1.0,1.0 -77154000.0,1.1,1.0,1.0 -77220000.0,1.1,1.0,1.0 -77286000.0,1.1,1.0,1.0 -77352000.0,1.1,1.0,1.0 -77418000.0,1.1,1.0,1.0 -77484000.0,1.1,1.0,1.0 -77550000.0,1.1,1.0,1.0 -77616000.0,1.1,1.0,1.0 -77682000.0,1.1,1.0,1.0 -77748000.0,1.1,1.0,1.0 -77814000.0,1.1,1.0,1.0 -77880000.0,1.1,1.0,1.0 -77946000.0,1.1,1.0,1.0 -78012000.0,1.1,1.0,1.0 -78078000.0,1.1,1.0,1.0 -78144000.0,1.1,1.0,1.0 -78210000.0,1.1,1.0,1.0 -78276000.0,1.1,1.0,1.0 -78342000.0,1.1,1.0,1.0 -78408000.0,1.1,1.0,1.0 -78474000.0,1.1,1.0,1.0 -78540000.0,1.1,1.0,1.0 -78606000.0,1.1,1.0,1.0 -78672000.0,1.1,1.0,1.0 -78738000.0,1.1,1.0,1.0 -78804000.0,1.1,1.0,1.0 -78870000.0,1.1,1.0,1.0 -78936000.0,1.1,1.0,1.0 -79002000.0,1.1,1.0,1.0 -79068000.0,1.1,1.0,1.0 -79134000.0,1.1,1.0,1.0 -79200000.0,1.1,1.0,1.0 -79266000.0,1.1,1.0,1.0 -79332000.0,1.1,1.0,1.0 -79398000.0,1.1,1.0,1.0 -79464000.0,1.1,1.0,1.0 -79530000.0,1.1,1.0,1.0 -79596000.0,1.1,1.0,1.0 -79662000.0,1.1,1.0,1.0 -79728000.0,1.1,1.0,1.0 -79794000.0,1.1,1.0,1.0 -79860000.0,1.1,1.0,1.0 -79926000.0,1.1,0.9998957355854446,0.9998957355854446 -79992000.0,1.1,0.9996872502360732,0.999791492910759 -80058000.0,1.1,0.9993746200108351,0.9996872719691441 -80124000.0,1.1,0.9989579535025962,0.9995830727538044 -80190000.0,1.1,0.9984373917759143,0.9994788952579469 -80256000.0,1.1,0.9978131082879343,0.9993747394747812 -80322000.0,1.1,0.9970853087924654,0.99927060539752 -80388000.0,1.1,0.9962542312273122,0.999166493019379 -80454000.0,1.1,0.9953201455849489,0.9990624023335765 -80520000.0,1.1,0.9942833537666311,0.9989583333333333 -80586000.0,1.1,0.9931441894200597,0.9988542860118738 -80652000.0,1.1,0.9919030177607137,0.9987502603624245 -80718000.0,1.1,0.9905602353769908,0.998646256378215 -80784000.0,1.1,0.9891162700192984,0.9985422740524781 -80850000.0,1.1,0.9875715803732504,0.9984383133784487 -80916000.0,1.1,0.9859266558171426,0.998334374349365 -80982000.0,1.1,0.9841820161638802,0.9982304569584678 -81048000.0,1.1,0.9823382113875533,0.9981265611990009 -81114000.0,1.1,0.9803958213348565,0.9980226870642106 -81180000.0,1.1,0.9783554554215684,0.9979188345473464 -81246000.0,1.1,0.9762177523143108,0.9978150036416606 -81312000.0,1.1,0.9739833795978193,0.9977111943404077 -81378000.0,1.1,0.9716530334279712,0.9976074066368459 -81444000.0,1.1,0.9692274381708178,0.9975036405242353 -81510000.0,1.1,0.9667073460278879,0.9973998959958398 -81576000.0,1.1,0.9640935366480288,0.9972961730449251 -81642000.0,1.1,0.961386816726068,0.9971924716647603 -81708000.0,1.1,0.958588019588583,0.9970887918486171 -81774000.0,1.1,0.9556980047670767,0.9969851335897703 -81840000.0,1.1,0.9527176575588633,0.9968814968814969 -81906000.0,1.1,0.9496478885759794,0.996777881717077 -81972000.0,1.1,0.9464896332824403,0.9966742880897941 -82038000.0,1.1,0.9432438515201707,0.9965707159929336 -82104000.0,1.1,0.9399115270239439,0.9964671654197838 -82170000.0,1.1,0.9364936669256748,0.9963636363636362 -82236000.0,1.1,0.9329913012484127,0.996260128817785 -82302000.0,1.1,0.9294054823903891,0.996156642775527 -82368000.0,1.1,0.9257372845994841,0.9960531782301622 -82434000.0,1.1,0.9219878034384726,0.9959497351749923 -82500000.0,1.1,0.9181581552414281,0.9958463136033229 -82566000.0,1.1,0.9142494765616546,0.9957429135084622 -82632000.0,1.1,0.910262923611531,0.9956395348837209 -82698000.0,1.1,0.9061996716946521,0.9955361777224127 -82764000.0,1.1,0.9020609146306532,0.9954328420178533 -82830000.0,1.1,0.8978478641731151,0.9953295277633628 -82896000.0,1.1,0.8935617494209395,0.9952262349522621 -82962000.0,1.1,0.8892038162235975,0.9951229635778769 -83028000.0,1.1,0.8847753265806494,0.9950197136335338 -83094000.0,1.1,0.8802775580359402,0.9949164851125636 -83160000.0,1.1,0.8757118030668741,0.9948132780082988 -83220000.0,1.0,0.8710793684691757,0.9947100923140753 -83280000.0,1.0,0.8663815747375434,0.9946069280232316 -83340000.0,1.0,0.861619755442605,0.9945037851291091 -83400000.0,1.0,0.8567952566045813,0.9944006636250519 -83460000.0,1.0,0.8519094360640679,0.9942975635044063 -83520000.0,1.0,0.8469636628503432,0.9941944847605224 -83580000.0,1.0,0.8419593165476097,0.9940914273867523 -83640000.0,1.0,0.8368977866595746,0.9939883913764509 -83700000.0,1.0,0.8317804719727764,0.9938853767229764 -83760000.0,1.0,0.8266087799190596,0.993782383419689 -83820000.0,1.0,0.8213841259376004,0.9936794114599523 -83880000.0,1.0,0.8161079328368822,0.9935764608371321 -83940000.0,1.0,0.8107816301570185,0.9934735315445975 -84000000.0,1.0,0.805406653532816,0.9933706235757197 -84060000.0,1.0,0.7999844440579705,0.9932677369238736 -84120000.0,1.0,0.7945164476507806,0.9931648715824357 -84180000.0,1.0,0.7890041144217651,0.9930620275447861 -84240000.0,1.0,0.7834488980435625,0.9929592048043073 -84300000.0,1.0,0.7778522551234873,0.9928564033543844 -84360000.0,1.0,0.7722156445791142,0.9927536231884058 -84420000.0,1.0,0.7665405270172554,0.9926508642997618 -84480000.0,1.0,0.760828364116692,0.9925481266818462 -84540000.0,1.0,0.7550806180150135,0.9924454103280553 -84600000.0,1.0,0.749298750699915,0.9923427152317881 -84660000.0,1.0,0.7434842234052959,0.9922400413864458 -84720000.0,1.0,0.737638496012496,0.9921373887854333 -84780000.0,1.0,0.7317630264570019,0.992034757422158 -84840000.0,1.0,0.7258592701409441,0.9919321472900289 -84900000.0,1.0,0.7199286793517069,0.9918295583824595 -84960000.0,1.0,0.7139727026869563,0.9917269906928643 -85020000.0,1.0,0.7079927844863935,0.9916244442146623 -85080000.0,1.0,0.7019903642705245,0.9915219189412737 -85140000.0,1.0,0.6959668761867394,0.9914194148661222 -85200000.0,1.0,0.6899237484629761,0.9913169319826339 -85260000.0,1.0,0.6838624028692445,0.9912144702842377 -85320000.0,1.0,0.6777842541872732,0.9911120297643655 -85380000.0,1.0,0.6716907096885346,0.9910096104164513 -85440000.0,1.0,0.6655831686208976,0.9909072122339326 -85500000.0,1.0,0.6594630217041438,0.990804835210249 -85560000.0,1.0,0.6533316506345804,0.9907024793388428 -85620000.0,1.0,0.6471904275989696,0.9906001446131596 -85680000.0,1.0,0.6410407147979879,0.9904978310266473 -85740000.0,1.0,0.634883863979418,0.9903955385727565 -85800000.0,1.0,0.62872121598127,0.99029326724494 -85860000.0,1.0,0.6225541002850159,0.9901910170366547 -85920000.0,1.0,0.6163838345791145,0.9900887879413588 -85980000.0,1.0,0.6102117243329934,0.9899865799525136 -86040000.0,1.0,0.6040390623816481,0.9898843930635838 -86100000.0,1.0,0.5978671285210037,0.9897822272680359 -86160000.0,1.0,0.5916971891141822,0.9896800825593397 -86220000.0,1.0,0.5855304967088028,0.9895779589309669 -86280000.0,1.0,0.5793682896654372,0.9894758563763927 -86340000.0,1.0,0.5732117917973324,0.9893737748890953 -86400000.0,1.0,0.5670622120214996,0.9892717144625541 -86460000.0,1.0,0.5609207440212668,0.9891696750902527 -86520000.0,1.0,0.5547885659203742,0.9890676567656764 -86580000.0,1.0,0.5486668399686901,0.9889656594823141 -86640000.0,1.0,0.54255671223961,0.9888636832336563 -86700000.0,1.0,0.5364593123391957,0.9887617280131972 -86760000.0,1.0,0.5303757531271017,0.9886597938144329 -86820000.0,1.0,0.5243071304493254,0.9885578806308629 -86880000.0,1.0,0.5182545228828108,0.9884559884559884 -86940000.0,1.0,0.5122189914919257,0.9883541172833143 -87000000.0,1.0,0.5062015795968227,0.9882522671063477 -87060000.0,1.0,0.5002033125536866,0.9881504379185984 -87120000.0,1.0,0.4942251975468632,0.9880486297135793 -87180000.0,1.0,0.48826822339285236,0.9879468424848047 -87240000.0,1.0,0.4823333603561447,0.9878450762257929 -87300000.0,1.0,0.4764215599768696,0.9877433309300646 -87360000.0,1.0,0.47053375491021404,0.987641606591143 -87420000.0,1.0,0.464670858777567,0.9875399032025538 -87480000.0,1.0,0.45883376602933146,0.9874382207578253 -87540000.0,1.0,0.45302335181934406,0.987336559250489 -87600000.0,1.0,0.4472404718908286,0.9872349186740785 -87660000.0,1.0,0.44148596247380817,0.9871332990221308 -87720000.0,1.0,0.4357606401938885,0.9870317002881845 -87780000.0,1.0,0.4300653019923218,0.9869301224657817 -87840000.0,1.0,0.42440072505725107,0.9868285655484668 -87900000.0,1.0,0.4187676667660292,0.9867270295297871 -87960000.0,1.0,0.4131668646385,0.9866255144032922 -88020000.0,1.0,0.4075990363011228,0.9865240201625347 -88080000.0,1.0,0.40206487946181524,0.9864225468010697 -88140000.0,1.0,0.39656507189538287,0.9863210943124548 -88200000.0,1.0,0.39110027143939957,0.9862196626902509 -88260000.0,1.0,0.38567111600039505,0.9861182519280206 -88320000.0,1.0,0.3802782235702024,0.9860168620193297 -88380000.0,1.0,0.37492219225231216,0.9859154929577463 -88440000.0,1.0,0.369603600298075,0.985814144736842 -88500000.0,1.0,0.3643230061525891,0.9857128173501902 -88560000.0,1.0,0.3590809485101058,0.9856115107913669 -88620000.0,1.0,0.3538779463787806,0.9855102250539511 -88680000.0,1.0,0.3487144991545937,0.9854089601315248 -88740000.0,1.0,0.34359108670425903,0.9853077160176718 -88800000.0,1.0,0.338508169456939,0.9852064927059792 -88860000.0,1.0,0.33346618850457577,0.9851052901900359 -88920000.0,1.0,0.3284655657106493,0.9850041084634346 -88980000.0,1.0,0.3235067038271672,0.98490294751977 -89040000.0,1.0,0.3185899866196892,0.9848018073526391 -89100000.0,1.0,0.31371577900018677,0.9847006879556421 -89160000.0,1.0,0.308884427167535,0.9845995893223819 -89220000.0,1.0,0.3040962587554317,0.9844985114464633 -89280000.0,1.0,0.2993515829875375,0.9843974543214946 -89340000.0,1.0,0.29465069083962686,0.9842964179410859 -89400000.0,1.0,0.28999385520854076,0.9841954022988504 -89460000.0,1.0,0.2853813310877277,0.9840944073884044 -89520000.0,1.0,0.28081335574915944,0.9839934332033653 -89580000.0,1.0,0.2762901489314086,0.9838924797373552 -89640000.0,1.0,0.27181191303366925,0.9837915469839966 -89700000.0,1.0,0.26737883331550805,0.9836906349369166 -89760000.0,1.0,0.26299107810212535,0.9835897435897436 -89820000.0,1.0,0.25864879899491156,0.9834888729361093 -89880000.0,1.0,0.25435213108707977,0.9833880229696473 -89940000.0,1.0,0.2501011931841582,0.9832871936839946 -90000000.0,1.0,0.24589608802912413,0.9831863850727905 -90060000.0,1.0,0.24173690253196312,0.983085597129677 -90120000.0,1.0,0.23762370800343652,0.9829848298482986 -90180000.0,1.0,0.23355656039284162,0.9828840832223017 -90240000.0,1.0,0.2295355005295502,0.982783357245337 -90300000.0,1.0,0.22556055436811012,0.9826826519110565 -90360000.0,1.0,0.22163173323669835,0.9825819672131146 -90420000.0,1.0,0.2177713444405673,0.9825819672131146 -90480000.0,1.0,0.2139781960230574,0.9825819672131146 -90540000.0,1.0,0.2102511167890492,0.9825819672131146 -90600000.0,1.0,0.2065889559433383,0.9825819672131146 -90660000.0,1.0,0.2029905827353088,0.9825819672131145 -90720000.0,1.0,0.19945488610979623,0.9825819672131146 -90780000.0,1.0,0.19598077436403133,0.9825819672131147 -90840000.0,1.0,0.19256717481055946,0.9825819672131147 -90900000.0,1.0,0.18921303344603124,0.9825819672131146 -90960000.0,1.0,0.18591731462576222,0.9825819672131145 -91020000.0,1.0,0.182679000743961,0.9825819672131146 -91080000.0,1.0,0.17949709191952723,0.9825819672131145 -91140000.0,1.0,0.17637060568732235,0.9825819672131147 -91200000.0,1.0,0.17329857669481774,0.9825819672131146 -91260000.0,1.0,0.17028005640402682,0.9825819672131145 -91320000.0,1.0,0.16731411279862882,0.9825819672131147 -91380000.0,1.0,0.16439983009619366,0.9825819672131146 -91440000.0,1.0,0.16153630846541978,0.9825819672131146 -91500000.0,1.0,0.15872266374829666,0.9825819672131146 -91560000.0,1.0,0.15595802718710705,0.9825819672131146 -91620000.0,1.0,0.15324154515618407,0.9825819672131147 -91680000.0,1.0,0.1505723788983407,0.9825819672131146 -91740000.0,1.0,0.14794970426589008,0.9825819672131147 -91800000.0,1.0,0.1453727114661768,0.9825819672131146 -91860000.0,1.0,0.1428406048115405,0.9825819672131146 -91920000.0,1.0,0.14035260247363457,0.9825819672131146 -91980000.0,1.0,0.13790793624202413,0.9825819672131147 -92040000.0,1.0,0.13550585128698886,0.9825819672131146 -92100000.0,1.0,0.13314560592645727,0.9825819672131146 -92160000.0,1.0,0.13082647139700054,0.9825819672131147 -92220000.0,1.0,0.12854773162881508,0.9825819672131147 -92280000.0,1.0,0.12630868302462464,0.9825819672131146 -92340000.0,1.0,0.12410863424243343,0.9825819672131147 -92400000.0,1.0,0.12194690598206316,0.9825819672131146 -92460000.0,1.0,0.11982283077540837,0.9825819672131147 -92520000.0,1.0,0.11773575278034487,0.9825819672131145 -92580000.0,1.0,0.1156850275782282,0.9825819672131146 -92640000.0,1.0,0.11367002197491888,0.9825819672131146 -92700000.0,1.0,0.11169011380527376,0.9825819672131146 -92760000.0,1.0,0.10974469174104254,0.9825819672131146 -92820000.0,1.0,0.10783315510211043,0.9825819672131146 -92880000.0,1.0,0.10595491367102858,0.9825819672131146 -92940000.0,1.0,0.104109387510775,0.9825819672131147 -93000000.0,1.0,0.10229600678568977,0.9825819672131146 -93060000.0,1.0,0.10051421158552919,0.9825819672131147 -93120000.0,1.0,0.09876345175258451,0.9825819672131146 -93180000.0,1.0,0.09704318671181203,0.9825819672131147 -93240000.0,1.0,0.09535288530392186,0.9825819672131147 -93300000.0,1.0,0.09369202562137403,0.9825819672131147 -93360000.0,1.0,0.09206009484723122,0.9825819672131145 -93420000.0,1.0,0.09045658909681838,0.9825819672131146 -93480000.0,1.0,0.08888101326214018,0.9825819672131146 -93540000.0,1.0,0.08733288085900863,0.9825819672131146 -93600000.0,1.0,0.08581171387683327,0.9825819672131147 -93660000.0,1.0,0.08431704263102777,0.9825819672131146 -93720000.0,1.0,0.08284840561798731,0.9825819672131146 -93780000.0,1.0,0.08140534937259203,0.9825819672131145 -93840000.0,1.0,0.07998742832819236,0.9825819672131146 -93900000.0,1.0,0.07859420467903326,0.9825819672131146 -93960000.0,1.0,0.07722524824507468,0.9825819672131146 -94020000.0,1.0,0.07588013633916661,0.9825819672131147 -94080000.0,1.0,0.07455845363653768,0.9825819672131146 -94140000.0,1.0,0.073259792046557,0.9825819672131146 -94200000.0,1.0,0.07198375058672966,0.9825819672131146 -94260000.0,1.0,0.07072993525888703,0.9825819672131146 -94320000.0,1.0,0.06949795892753347,0.9825819672131147 -94380000.0,1.0,0.06828744120031208,0.9825819672131146 -94440000.0,1.0,0.06709800831055253,0.9825819672131145 -94500000.0,1.0,0.06592929300186462,0.9825819672131146 -94560000.0,1.0,0.06478093441474196,0.9825819672131145 -94620000.0,1.0,0.06365257797514091,0.9825819672131146 -94680000.0,1.0,0.06254387528500013,0.9825819672131146 -94740000.0,1.0,0.06145448401466714,0.9825819672131147 -94800000.0,1.0,0.06038406779719854,0.9825819672131146 -94860000.0,1.0,0.05933229612450143,0.9825819672131146 -94920000.0,1.0,0.05829884424528368,0.9825819672131147 -94980000.0,1.0,0.05728339306478181,0.9825819672131146 -95040000.0,1.0,0.056285629046235394,0.9825819672131146 -95100000.0,1.0,0.0553052441140776,0.9825819672131146 -95160000.0,1.0,0.054341935558811894,0.9825819672131146 -95220000.0,1.0,0.05339540594354569,0.9825819672131145 -95280000.0,1.0,0.05246536301215196,0.9825819672131146 -95340000.0,1.0,0.051551519599030454,0.9825819672131146 -95400000.0,1.0,0.05065359354044078,0.9825819672131146 -95460000.0,1.0,0.04977130758737981,0.9825819672131145 -95520000.0,1.0,0.04890438931997667,0.9825819672131145 -95580000.0,1.0,0.048052571063378714,0.9825819672131147 -95640000.0,1.0,0.047215589805102647,0.9825819672131146 -95700000.0,1.0,0.046393187113825236,0.9825819672131146 -95760000.0,1.0,0.04558510905958852,0.9825819672131146 -95820000.0,1.0,0.044791106135394866,0.9825819672131147 -95880000.0,1.0,0.044010933180167695,0.9825819672131146 -95940000.0,1.0,0.04324434930305411,0.9825819672131145 -96000000.0,1.0,0.04249111780904599,0.9825819672131146 -96060000.0,1.0,0.04175100612589662,0.9825819672131146 -96120000.0,1.0,0.041023785732310296,0.9825819672131145 -96180000.0,1.0,0.04030923208738276,0.9825819672131147 -96240000.0,1.0,0.03960712456127056,0.9825819672131146 -96300000.0,1.0,0.0389172463670681,0.9825819672131147 -96360000.0,1.0,0.038239384493871216,0.9825819672131147 -96420000.0,1.0,0.03757332964100665,0.9825819672131146 -96480000.0,1.0,0.03691887615340715,0.9825819672131147 -96540000.0,1.0,0.036275821958112145,0.9825819672131146 -96600000.0,1.0,0.03564396850187453,0.9825819672131146 -96660000.0,1.0,0.03502312068985417,0.9825819672131146 -96720000.0,1.0,0.03441308682537925,0.9825819672131145 -96780000.0,1.0,0.03381367855075686,0.9825819672131146 -96840000.0,1.0,0.03322471078911457,0.9825819672131146 -96900000.0,1.0,0.03264600168725499,0.9825819672131146 -96960000.0,1.0,0.032077372559505664,0.9825819672131145 -97020000.0,1.0,0.031518647832547056,0.9825819672131146 -97080000.0,1.0,0.03096965499120146,0.9825819672131147 -97140000.0,1.0,0.030430224525166187,0.9825819672131146 -97200000.0,1.0,0.029900189876674556,0.9825819672131145 -97260000.0,1.0,0.02937938738906854,0.9825819672131146 -97320000.0,1.0,0.028867656256267134,0.9825819672131145 -97380000.0,1.0,0.028364838473114936,0.9825819672131146 -97440000.0,1.0,0.027870778786595513,0.9825819672131146 -97500000.0,1.0,0.027385324647894563,0.9825819672131146 -97560000.0,1.0,0.026908326165298035,0.9825819672131146 -97620000.0,1.0,0.02643963605791067,0.9825819672131146 -97680000.0,1.0,0.025979109610180663,0.9825819672131146 -97740000.0,1.0,0.025526604627216447,0.9825819672131146 -97800000.0,1.0,0.02508198139088173,0.9825819672131145 -97860000.0,1.0,0.024645102616655305,0.9825819672131147 -97920000.0,1.0,0.024215833411242248,0.9825819672131146 -97980000.0,1.0,0.023794041230923477,0.9825819672131146 -98040000.0,1.0,0.023379595840630752,0.9825819672131147 -98100000.0,1.0,0.022972369273734517,0.9825819672131146 -98160000.0,1.0,0.02257223579253217,0.9825819672131146 -98220000.0,1.0,0.022179071849424536,0.9825819672131145 -98280000.0,1.0,0.021792756048768572,0.9825819672131146 -98340000.0,1.0,0.021413169109394527,0.9825819672131146 -98400000.0,1.0,0.021040193827775975,0.9825819672131147 -98460000.0,1.0,0.02067371504184135,0.9825819672131145 -98520000.0,1.0,0.02031361959541583,0.9825819672131145 -98580000.0,1.0,0.01995979630328256,0.9825819672131147 -98640000.0,1.0,0.019612135916852434,0.9825819672131147 -98700000.0,1.0,0.019270531090431847,0.9825819672131146 -98760000.0,1.0,0.01893487634807801,0.9825819672131146 -98820000.0,1.0,0.018605068051031567,0.9825819672131146 -98880000.0,1.0,0.018281004365716464,0.9825819672131145 -98940000.0,1.0,0.01796258523229722,0.9825819672131146 -99000000.0,1.0,0.017649712333783842,0.9825819672131145 -99060000.0,1.0,0.0173422890656749,0.9825819672131146 -99120000.0,1.0,0.01704022050612933,0.9825819672131146 -99180000.0,1.0,0.016743413386657816,0.9825819672131147 -99240000.0,1.0,0.016451776063324635,0.9825819672131146 -99300000.0,1.0,0.01616521848845115,0.9825819672131145 -99360000.0,1.0,0.015883652182812142,0.9825819672131146 -99420000.0,1.0,0.015606990208316435,0.9825819672131145 -99480000.0,1.0,0.01533514714116338,0.9825819672131146 -99540000.0,1.0,0.015068039045466884,0.9825819672131145 -99600000.0,1.0,0.014805583447338871,0.9825819672131145 -99660000.0,1.0,0.014547699309424155,0.9825819672131146 -99720000.0,1.0,0.014294307005878856,0.9825819672131146 -99780000.0,1.0,0.014045328297784652,0.9825819672131146 -99840000.0,1.0,0.013800686308991271,0.9825819672131147 -99900000.0,1.0,0.01356030550237974,0.9825819672131145 -99960000.0,1.0,0.013324111656539107,0.9825819672131146 -100020000.0,1.0,0.013092031842849388,0.9825819672131146 -100080000.0,1.0,0.012863994402963689,0.9825819672131145 -100140000.0,1.0,0.012639928926682557,0.9825819672131146 -100200000.0,1.0,0.0124197662302137,0.9825819672131146 -100260000.0,1.0,0.012203438334810385,0.9825819672131145 -100320000.0,1.0,0.011990878445781925,0.9825819672131147 -100380000.0,1.0,0.011782020931869738,0.9825819672131146 -100440000.0,1.0,0.011576801304982662,0.9825819672131146 -100500000.0,1.0,0.011375156200285216,0.9825819672131146 -100560000.0,1.0,0.011177023356632705,0.9825819672131145 -100620000.0,1.0,0.010982341597347093,0.9825819672131146 -100680000.0,1.0,0.010791050811327727,0.9825819672131146 -100740000.0,1.0,0.010603091934491075,0.9825819672131146 -100800000.0,1.0,0.01041840693153375,0.9825819672131146 -100860000.0,1.0,0.010236938778013181,0.9825819672131146 -100920000.0,1.0,0.010058631442740409,0.9825819672131146 -100980000.0,1.0,0.00988342987047956,0.9825819672131146 -101040000.0,1.0,0.009711279964948666,0.9825819672131146 -101100000.0,1.0,0.009542128572116566,0.9825819672131145 -101160000.0,1.0,0.009375923463790764,0.9825819672131146 -101220000.0,1.0,0.009212613321491129,0.9825819672131146 -101280000.0,1.0,0.0090521477206045,0.9825819672131146 -101340000.0,1.0,0.008894477114815282,0.9825819672131147 -101400000.0,1.0,0.008739552820807227,0.9825819672131145 -101460000.0,1.0,0.00858732700323169,0.9825819672131145 -101520000.0,1.0,0.008437752659937695,0.9825819672131146 -101580000.0,1.0,0.00829078360745927,0.9825819672131145 -101640000.0,1.0,0.008146374466755573,0.9825819672131146 -101700000.0,1.0,0.00800448064919938,0.9825819672131147 -101760000.0,1.0,0.007865058342809634,0.9825819672131145 -101820000.0,1.0,0.00772806449872381,0.9825819672131147 -101880000.0,1.0,0.007593456817905873,0.9825819672131145 -101940000.0,1.0,0.007461193738085791,0.9825819672131146 -102000000.0,1.0,0.00733123442092651,0.9825819672131147 -102060000.0,1.0,0.007203538739414469,0.9825819672131145 -102120000.0,1.0,0.007078067265469749,0.9825819672131146 -102180000.0,1.0,0.006954781257772017,0.9825819672131147 -102240000.0,1.0,0.006833642649798528,0.9825819672131146 -102300000.0,1.0,0.006714614038070479,0.9825819672131145 -102360000.0,1.0,0.006597658670604086,0.9825819672131146 -102420000.0,1.0,0.006482740435562825,0.9825819672131145 -102480000.0,1.0,0.006369823850107325,0.9825819672131147 -102540000.0,1.0,0.006258874049439471,0.9825819672131146 -102600000.0,1.0,0.006149856776037348,0.9825819672131145 -102660000.0,1.0,0.0060427383690776805,0.9825819672131147 -102720000.0,1.0,0.005937485754042515,0.9825819672131146 -102780000.0,1.0,0.005834066432506938,0.9825819672131146 -102840000.0,1.0,0.0057324484721046655,0.9825819672131147 -102900000.0,1.0,0.005632600496668416,0.9825819672131147 -102960000.0,1.0,0.005534491676542019,0.9825819672131147 -103020000.0,1.0,0.005438091719061266,0.9825819672131146 -103080000.0,1.0,0.0053433708592005675,0.9825819672131146 -103140000.0,1.0,0.005250299850382525,0.9825819672131147 -103200000.0,1.0,0.005158849955447582,0.9825819672131145 -103260000.0,1.0,0.005068992937780974,0.9825819672131146 -103320000.0,1.0,0.004980701052594215,0.9825819672131147 -103380000.0,1.0,0.0048939470383584545,0.9825819672131146 -103440000.0,1.0,0.004808704108387046,0.9825819672131146 -103500000.0,1.0,0.00472494594256473,0.9825819672131145 -103560000.0,1.0,0.004642646679220877,0.9825819672131147 -103620000.0,1.0,0.004561780907144283,0.9825819672131146 -103680000.0,1.0,0.004482323657737056,0.9825819672131145 -103740000.0,1.0,0.0044042503973051594,0.9825819672131145 -103800000.0,1.0,0.004327537019483245,0.9825819672131146 -103860000.0,1.0,0.004252159837791426,0.9825819672131146 -103920000.0,1.0,0.0041780955783216975,0.9825819672131146 -103980000.0,1.0,0.004105321372551749,0.9825819672131146 -104040000.0,1.0,0.004033814750283942,0.9825819672131146 -104100000.0,1.0,0.0039635536327072745,0.9825819672131146 -104160000.0,1.0,0.0038945163255802006,0.9825819672131146 -104220000.0,1.0,0.003826681512532184,0.9825819672131145 -104280000.0,1.0,0.0037600282484819307,0.9825819672131147 -104340000.0,1.0,0.0036945359531702577,0.9825819672131147 -104400000.0,1.0,0.0036301844048056116,0.9825819672131147 -104460000.0,1.0,0.0035669537338202674,0.9825819672131146 -104520000.0,1.0,0.0035048244167352827,0.9825819672131146 -104580000.0,1.0,0.003443777270132311,0.9825819672131145 -104640000.0,1.0,0.0033837934447304156,0.9825819672131146 -104700000.0,1.0,0.0033248544195660537,0.9825819672131147 -104760000.0,1.0,0.003266941996274431,0.9825819672131145 -104820000.0,1.0,0.0032100382934704703,0.9825819672131146 -104880000.0,1.0,0.003154125741227644,0.9825819672131146 -104940000.0,1.0,0.003099187075652982,0.9825819672131146 -105000000.0,1.0,0.003045205333556567,0.9825819672131146 -105060000.0,1.0,0.00299216384721388,0.9825819672131145 -105120000.0,1.0,0.002940046239219376,0.9825819672131147 -105180000.0,1.0,0.002888836417429694,0.9825819672131147 -105240000.0,1.0,0.0028385185699949553,0.9825819672131146 -105300000.0,1.0,0.0027890771604766004,0.9825819672131147 -105360000.0,1.0,0.002740496923050266,0.9825819672131146 -105420000.0,1.0,0.002692762857792218,0.9825819672131146 -105480000.0,1.0,0.002645860226047886,0.9825819672131146 -105540000.0,1.0,0.002599774545881068,0.9825819672131145 -105600000.0,1.0,0.0025544915876024015,0.9825819672131147 -105660000.0,1.0,0.00250999736937572,0.9825819672131146 -105720000.0,1.0,0.0024662781529009377,0.9825819672131146 -105780000.0,1.0,0.00242332043917213,0.9825819672131146 -105840000.0,1.0,0.0023811109643095004,0.9825819672131145 -105900000.0,1.0,0.0023396366954639455,0.9825819672131147 -105960000.0,1.0,0.0022988848267929546,0.9825819672131147 -106020000.0,1.0,0.0022588427755066017,0.9825819672131146 -106080000.0,1.0,0.0022194981779824086,0.9825819672131146 -106140000.0,1.0,0.002180838885947879,0.9825819672131147 -106200000.0,1.0,0.002142852962729524,0.9825819672131145 -106260000.0,1.0,0.0021055286795672265,0.9825819672131145 -106320000.0,1.0,0.0020688545119927973,0.9825819672131147 -106380000.0,1.0,0.0020328191362716107,0.9825819672131145 -106440000.0,1.0,0.0019974114259062236,0.9825819672131145 -106500000.0,1.0,0.0019626204482008896,0.9825819672131146 -106560000.0,1.0,0.0019284354608859148,0.9825819672131146 -106620000.0,1.0,0.0018948459088008113,0.9825819672131145 -106680000.0,1.0,0.001861841420635223,0.9825819672131145 -106740000.0,1.0,0.0018294118057266173,0.9825819672131145 -106800000.0,1.0,0.001797547050913756,0.9825819672131147 -106860000.0,1.0,0.001766237317444971,0.9825819672131145 -106920000.0,1.0,0.001735472937940294,0.9825819672131146 -106980000.0,1.0,0.0017052444134064977,0.9825819672131146 -107040000.0,1.0,0.0016755424103041302,0.9825819672131146 -107100000.0,1.0,0.001646357757665636,0.9825819672131146 -107160000.0,1.0,0.0016176814442636729,0.9825819672131146 -107220000.0,1.0,0.0015895046158287522,0.9825819672131146 -107280000.0,1.0,0.0015618185723153414,0.9825819672131146 -107340000.0,1.0,0.0015346147652155863,0.9825819672131146 -107400000.0,1.0,0.0015078847949198228,0.9825819672131146 -107460000.0,1.0,0.0014816204081230635,0.9825819672131146 -107520000.0,1.0,0.0014558134952766576,0.9825819672131147 -107580000.0,1.0,0.0014304560880843387,0.9825819672131147 -107640000.0,1.0,0.001405540357041886,0.9825819672131146 -107700000.0,1.0,0.0013810586090196397,0.9825819672131146 -107760000.0,1.0,0.0013570032848871255,0.9825819672131147 -107820000.0,1.0,0.0013333669571790503,0.9825819672131146 -107880000.0,1.0,0.0013101423278019562,0.9825819672131147 -107940000.0,1.0,0.0012873222257808153,0.9825819672131145 -108000000.0,1.0,0.0012648996050448789,0.9825819672131146 -108060000.0,1.0,0.0012428675422520889,0.9825819672131146 -108120000.0,1.0,0.0012212192346513864,0.9825819672131146 -108180000.0,1.0,0.0011999479979822535,0.9825819672131146 -108240000.0,1.0,0.0011790472644108412,0.9825819672131146 -108300000.0,1.0,0.0011585105805020457,0.9825819672131146 -108360000.0,1.0,0.0011383316052269075,0.9825819672131146 -108420000.0,1.0,0.0011185041080047173,0.9825819672131146 -108480000.0,1.0,0.0010990219667792252,0.9825819672131146 -108540000.0,1.0,0.0010798791661283573,0.9825819672131145 -108600000.0,1.0,0.001061069795406859,0.9825819672131145 -108660000.0,1.0,0.0010425880469212886,0.9825819672131145 -108720000.0,1.0,0.001024428214136799,0.9825819672131149 -108780000.0,1.0,0.0010065846899151537,0.9825819672131145 -108840000.0,1.0,0.0009890519647834347,0.9825819672131146 -108900000.0,1.0,0.0009718246252329035,0.9825819672131146 -108960000.0,1.0,0.0009548973520474941,0.9825819672131146 -109020000.0,1.0,0.0009382649186614209,0.9825819672131146 -109080000.0,1.0,0.0009219221895453919,0.9825819672131146 -109140000.0,1.0,0.0009058641186209332,0.9825819672131147 -109200000.0,1.0,0.0008900857477023308,0.9825819672131146 -109260000.0,1.0,0.0008745822049657123,0.9825819672131147 -109320000.0,1.0,0.0008593487034447931,0.9825819672131147 -109380000.0,1.0,0.0008443805395528243,0.9825819672131147 -109440000.0,1.0,0.0008296730916302853,0.9825819672131147 -109500000.0,1.0,0.0008152218185178725,0.9825819672131146 -109560000.0,1.0,0.0008010222581543439,0.9825819672131146 -109620000.0,1.0,0.0007870700261987866,0.9825819672131146 -109680000.0,1.0,0.0007733608146768814,0.9825819672131145 -109740000.0,1.0,0.0007598903906507471,0.9825819672131147 -109800000.0,1.0,0.0007466545949119534,0.9825819672131147 -109860000.0,1.0,0.0007336493406972985,0.9825819672131147 -109920000.0,1.0,0.000720870612426956,0.9825819672131145 -109980000.0,1.0,0.0007083144644646011,0.9825819672131146 -110040000.0,1.0,0.0006959770198991316,0.9825819672131146 -110100000.0,1.0,0.0006838544693476097,0.9825819672131146 -110160000.0,1.0,0.000671943069779055,0.9825819672131146 -110220000.0,1.0,0.000660239143358723,0.9825819672131146 -110280000.0,1.0,0.0006487390763125156,0.9825819672131146 -110340000.0,1.0,0.0006374393178111706,0.9825819672131147 -110400000.0,1.0,0.0006263363788738857,0.9825819672131146 -110460000.0,1.0,0.0006154268312910413,0.9825819672131145 -110520000.0,1.0,0.000604707306565685,0.9825819672131146 -110580000.0,1.0,0.0005941744948734547,0.9825819672131145 -110640000.0,1.0,0.0005838251440406178,0.9825819672131147 -110700000.0,1.0,0.0005736560585399103,0.9825819672131147 -110760000.0,1.0,0.0005636640985038667,0.9825819672131146 -110820000.0,1.0,0.0005538461787553361,0.9825819672131146 -110880000.0,1.0,0.0005441992678548845,0.9825819672131146 -110940000.0,1.0,0.0005347203871647892,0.9825819672131147 -111000000.0,1.0,0.0005254066099293368,0.9825819672131145 -111060000.0,1.0,0.0005162550603711413,0.9825819672131146 -111120000.0,1.0,0.0005072629128032013,0.9825819672131145 -111180000.0,1.0,0.0004984273907564241,0.9825819672131146 -111240000.0,1.0,0.000489745766122347,0.9825819672131145 -111300000.0,1.0,0.0004812153583107897,0.9825819672131147 -111360000.0,1.0,0.00047283353342217956,0.9825819672131146 -111420000.0,1.0,0.00046459770343429315,0.9825819672131145 -111480000.0,1.0,0.000456505325403163,0.9825819672131146 -111540000.0,1.0,0.0004485539006779029,0.9825819672131146 -111600000.0,1.0,0.0004407409741292098,0.9825819672131145 -111660000.0,1.0,0.0004330641333913034,0.9825819672131145 -111720000.0,1.0,0.0004255210081170696,0.9825819672131146 -111780000.0,1.0,0.000418109269246178,0.9825819672131146 -111840000.0,1.0,0.0004108266282859474,0.9825819672131146 -111900000.0,1.0,0.0004036708366047372,0.9825819672131146 -111960000.0,1.0,0.0003966396847376465,0.9825819672131146 -112020000.0,1.0,0.0003897310017043063,0.9825819672131146 -112080000.0,1.0,0.000382942654338555,0.9825819672131146 -112140000.0,1.0,0.00037627254662978915,0.9825819672131146 -112200000.0,1.0,0.0003697186190757867,0.9825819672131147 -112260000.0,1.0,0.0003632788480468026,0.9825819672131146 -112320000.0,1.0,0.00035695124516074147,0.9825819672131146 -112380000.0,1.0,0.0003507338566692121,0.9825819672131146 -112440000.0,1.0,0.00034462476285427706,0.9825819672131147 -112500000.0,1.0,0.0003386220774357087,0.9825819672131146 -112560000.0,1.0,0.0003327239469885703,0.9825819672131146 -112620000.0,1.0,0.00032692855037094146,0.9825819672131146 -112680000.0,1.0,0.0003212340981616115,0.9825819672131146 -112740000.0,1.0,0.00031563883210756696,0.9825819672131145 -112800000.0,1.0,0.00031014102458110316,0.9825819672131146 -112860000.0,1.0,0.00030473897804639125,0.9825819672131145 -112920000.0,1.0,0.00029943102453533726,0.9825819672131146 -112980000.0,1.0,0.0002942155251325701,0.9825819672131146 -113040000.0,1.0,0.00028909086946940027,0.9825819672131145 -113100000.0,1.0,0.00028405547522659307,0.9825819672131146 -113160000.0,1.0,0.000279107787645802,0.9825819672131147 -113220000.0,1.0,0.00027424627904951236,0.9825819672131145 -113280000.0,1.0,0.00026946944836934663,0.9825819672131146 -113340000.0,1.0,0.00026477582068258545,0.9825819672131146 -113400000.0,1.0,0.0002601639467567617,0.9825819672131146 -113460000.0,1.0,0.00025563240260218693,0.9825819672131147 -113520000.0,1.0,0.0002511797890322718,0.9825819672131147 -113580000.0,1.0,0.00024680473123150475,0.9825819672131147 -113640000.0,1.0,0.00024250587833095596,0.9825819672131146 -113700000.0,1.0,0.00023828190299117493,0.9825819672131146 -113760000.0,1.0,0.00023413150099235318,0.9825819672131145 -113820000.0,1.0,0.00023005339083162572,0.9825819672131147 -113880000.0,1.0,0.00022604631332738632,0.9825819672131146 -113940000.0,1.0,0.00022210903123049536,0.9825819672131147 -114000000.0,1.0,0.00021824032884225925,0.9825819672131146 -114060000.0,1.0,0.00021443901163906414,0.9825819672131146 -114120000.0,1.0,0.00021070390590354764,0.9825819672131147 -114180000.0,1.0,0.00020703385836219485,0.9825819672131146 -114240000.0,1.0,0.00020342773582924677,0.9825819672131146 -114300000.0,1.0,0.00019988442485681108,0.9825819672131146 -114360000.0,1.0,0.0001964028313910674,0.9825819672131145 -114420000.0,1.0,0.0001929818804344607,0.9825819672131147 -114480000.0,1.0,0.00018962051571377848,0.9825819672131147 -114540000.0,1.0,0.00018631769935400976,0.9825819672131145 -114600000.0,1.0,0.00018307241155788459,0.9825819672131147 -114660000.0,1.0,0.0001798836502909952,0.9825819672131146 -114720000.0,1.0,0.000176750430972402,0.9825819672131146 -114780000.0,1.0,0.0001736717861706286,0.9825819672131146 -114840000.0,1.0,0.00017064676530495165,0.9825819672131146 -114900000.0,1.0,0.00016767443435189409,0.9825819672131147 -114960000.0,1.0,0.00016475387555683034,0.9825819672131146 -115020000.0,1.0,0.00016188418715061504,0.9825819672131146 -115080000.0,1.0,0.00015906448307114734,0.9825819672131146 -115140000.0,1.0,0.00015629389268978513,0.9825819672131146 -115200000.0,1.0,0.0001535715605425245,0.9825819672131145 -115260000.0,1.0,0.00015089664606586164,0.9825819672131145 -115320000.0,1.0,0.00014826832333725542,0.9825819672131145 -115380000.0,1.0,0.00014568578082011058,0.9825819672131146 -115440000.0,1.0,0.00014314822111320292,0.9825819672131147 -115500000.0,1.0,0.00014065486070446884,0.9825819672131146 -115560000.0,1.0,0.0001382049297290836,0.9825819672131146 -115620000.0,1.0,0.00013579767173175323,0.9825819672131145 -115680000.0,1.0,0.00013343234343314686,0.9825819672131146 -115740000.0,1.0,0.00013110821450039738,0.9825819672131147 -115800000.0,1.0,0.00012882456732159943,0.9825819672131144 -115860000.0,1.0,0.0001265806967842355,0.9825819672131147 -115920000.0,1.0,0.0001243759100574609,0.9825819672131146 -115980000.0,1.0,0.00012220952637818133,0.9825819672131145 -116040000.0,1.0,0.00012008087684085644,0.9825819672131146 -116100000.0,1.0,0.00011798930419096445,0.9825819672131145 -116160000.0,1.0,0.00011593416262206445,0.9825819672131147 -116220000.0,1.0,0.00011391481757639323,0.9825819672131146 -116280000.0,1.0,0.00011193064554893556,0.9825819672131147 -116340000.0,1.0,0.00010998103389490696,0.9825819672131146 -116400000.0,1.0,0.00010806538064058992,0.9825819672131146 -116460000.0,1.0,0.00010618309429746488,0.9825819672131146 -116520000.0,1.0,0.00010433359367957869,0.9825819672131145 -116580000.0,1.0,0.0001025163077240942,0.9825819672131145 -116640000.0,1.0,0.00010073067531496551,0.9825819672131146 -116700000.0,1.0,9.897614510968433e-05,0.9825819672131145 -116760000.0,1.0,9.725217536904433e-05,0.9825819672131147 -116820000.0,1.0,9.555823378987039e-05,0.9825819672131146 -116880000.0,1.0,9.389379734066157e-05,0.9825819672131146 -116940000.0,1.0,9.225835210009676e-05,0.9825819672131146 -117000000.0,1.0,9.065139309835325e-05,0.9825819672131145 -117060000.0,1.0,8.907242416118929e-05,0.9825819672131145 -117120000.0,1.0,8.752095775674234e-05,0.9825819672131146 -117180000.0,1.0,8.59965148449958e-05,0.9825819672131147 -117240000.0,1.0,8.449862472986779e-05,0.9825819672131146 -117300000.0,1.0,8.302682491387624e-05,0.9825819672131147 -117360000.0,1.0,8.158066095533535e-05,0.9825819672131146 -117420000.0,1.0,8.015968632803954e-05,0.9825819672131147 -117480000.0,1.0,7.87634622833913e-05,0.9825819672131146 -117540000.0,1.0,7.739155771493057e-05,0.9825819672131145 -117600000.0,1.0,7.604354902522378e-05,0.9825819672131146 -117660000.0,1.0,7.471901999507131e-05,0.9825819672131147 -117720000.0,1.0,7.341756165499322e-05,0.9825819672131146 -117780000.0,1.0,7.213877215895336e-05,0.9825819672131145 -117840000.0,1.0,7.088225666028305e-05,0.9825819672131145 -117900000.0,1.0,6.964762718976581e-05,0.9825819672131146 -117960000.0,1.0,6.84345025358457e-05,0.9825819672131146 -118020000.0,1.0,6.724250812692215e-05,0.9825819672131145 -118080000.0,1.0,6.607127591569502e-05,0.9825819672131147 -118140000.0,1.0,6.49204442655241e-05,0.9825819672131147 -118200000.0,1.0,6.378965783876803e-05,0.9825819672131145 -118260000.0,1.0,6.267856748706817e-05,0.9825819672131146 -118320000.0,1.0,6.158683014354341e-05,0.9825819672131146 -118380000.0,1.0,6.051410871686284e-05,0.9825819672131147 -118440000.0,1.0,5.946007198716338e-05,0.9825819672131146 -118500000.0,1.0,5.842439450378041e-05,0.9825819672131147 -118560000.0,1.0,5.740675648475964e-05,0.9825819672131147 -118620000.0,1.0,5.640684371811936e-05,0.9825819672131147 -118680000.0,1.0,5.5424347464832436e-05,0.9825819672131146 -118740000.0,1.0,5.445896436349826e-05,0.9825819672131147 -118800000.0,1.0,5.351039633667503e-05,0.9825819672131146 -118860000.0,1.0,5.2578350498843596e-05,0.9825819672131147 -118920000.0,1.0,5.166253906597439e-05,0.9825819672131146 -118980000.0,1.0,5.07626792666695e-05,0.9825819672131146 -119040000.0,1.0,4.987849325485251e-05,0.9825819672131146 -119100000.0,1.0,4.900970802397905e-05,0.9825819672131146 -119160000.0,1.0,4.81560553227417e-05,0.9825819672131145 -119220000.0,1.0,4.7317271572243115e-05,0.9825819672131145 -119280000.0,1.0,4.6493097784611825e-05,0.9825819672131146 -119340000.0,1.0,4.5683279483035594e-05,0.9825819672131147 -119400000.0,1.0,4.488756662318763e-05,0.9825819672131146 -119460000.0,1.0,4.4105713516021446e-05,0.9825819672131145 -119520000.0,1.0,4.333747875191041e-05,0.9825819672131146 -119580000.0,1.0,4.258262512610869e-05,0.9825819672131146 -119640000.0,1.0,4.1840919565510475e-05,0.9825819672131145 -119700000.0,1.0,4.1112133056684975e-05,0.9825819672131145 -119760000.0,1.0,4.039604057516484e-05,0.9825819672131146 -119820000.0,1.0,3.969242101596627e-05,0.9825819672131146 -119880000.0,1.0,3.9001057125319315e-05,0.9825819672131147 -119940000.0,1.0,3.8321735433587314e-05,0.9825819672131146 -120000000.0,1.0,3.7654246189354746e-05,0.9825819672131146 -120060000.0,1.0,3.699838329466311e-05,0.9825819672131146 -120120000.0,1.0,3.6353944241374925e-05,0.9825819672131147 -120180000.0,1.0,3.572073004864606e-05,0.9825819672131147 -120240000.0,1.0,3.509854520148726e-05,0.9825819672131145 -120300000.0,1.0,3.448719759039578e-05,0.9825819672131147 -120360000.0,1.0,3.3886498452038475e-05,0.9825819672131147 -120420000.0,1.0,3.329626231096813e-05,0.9825819672131146 -120480000.0,1.0,3.271630692235495e-05,0.9825819672131147 -120540000.0,1.0,3.2146453215715574e-05,0.9825819672131147 -120600000.0,1.0,3.158652523962216e-05,0.9825819672131145 -120660000.0,1.0,3.1036350107374636e-05,0.9825819672131145 -120720000.0,1.0,3.049575794361913e-05,0.9825819672131146 -120780000.0,1.0,2.996458183189625e-05,0.9825819672131145 -120840000.0,1.0,2.944265776310297e-05,0.9825819672131146 -120900000.0,1.0,2.89298245848522e-05,0.9825819672131146 -120960000.0,1.0,2.84259239517144e-05,0.9825819672131146 -121020000.0,1.0,2.793080027632593e-05,0.9825819672131146 -121080000.0,1.0,2.7444300681348936e-05,0.9825819672131146 -121140000.0,1.0,2.696627495226806e-05,0.9825819672131146 -121200000.0,1.0,2.649657549100929e-05,0.9825819672131146 -121260000.0,1.0,2.6035057270366706e-05,0.9825819672131146 -121320000.0,1.0,2.558157778922302e-05,0.9825819672131146 -121380000.0,1.0,2.5135997028550072e-05,0.9825819672131145 -121440000.0,1.0,2.4698177408175732e-05,0.9825819672131145 -121500000.0,1.0,2.4267983744303818e-05,0.9825819672131147 -121560000.0,1.0,2.3845283207773933e-05,0.9825819672131146 -121620000.0,1.0,2.3429945283048362e-05,0.9825819672131147 -121680000.0,1.0,2.3021841727913294e-05,0.9825819672131145 -121740000.0,1.0,2.2620846533882015e-05,0.9825819672131146 -121800000.0,1.0,2.2226835887287756e-05,0.9825819672131146 -121860000.0,1.0,2.1839688131054256e-05,0.9825819672131146 -121920000.0,1.0,2.14592837271322e-05,0.9825819672131146 -121980000.0,1.0,2.1085505219589938e-05,0.9825819672131146 -122040000.0,1.0,2.0718237198347075e-05,0.9825819672131145 -122100000.0,1.0,2.0357366263539797e-05,0.9825819672131146 -122160000.0,1.0,2.0002780990506826e-05,0.9825819672131146 -122220000.0,1.0,1.965437189538529e-05,0.9825819672131146 -122280000.0,1.0,1.9312031401305832e-05,0.9825819672131146 -122340000.0,1.0,1.8975653805176526e-05,0.9825819672131145 -122400000.0,1.0,1.8645135245045376e-05,0.9825819672131146 -122460000.0,1.0,1.8320373668031265e-05,0.9825819672131146 -122520000.0,1.0,1.8001268798813505e-05,0.9825819672131146 -122580000.0,1.0,1.7687722108670238e-05,0.9825819672131147 -122640000.0,1.0,1.7379636785056103e-05,0.9825819672131146 -122700000.0,1.0,1.7076917701709834e-05,0.9825819672131145 -122760000.0,1.0,1.677947138928251e-05,0.9825819672131146 -122820000.0,1.0,1.6487206006477383e-05,0.9825819672131146 -122880000.0,1.0,1.6200031311692426e-05,0.9825819672131146 -122940000.0,1.0,1.5917858635156797e-05,0.9825819672131146 -123000000.0,1.0,1.564060085155263e-05,0.9825819672131147 -123060000.0,1.0,1.53681723531137e-05,0.9825819672131146 -123120000.0,1.0,1.5100489023192662e-05,0.9825819672131147 -123180000.0,1.0,1.4837468210288691e-05,0.9825819672131147 -123240000.0,1.0,1.4579028702527514e-05,0.9825819672131146 -123300000.0,1.0,1.4325090702585948e-05,0.9825819672131146 -123360000.0,1.0,1.4075575803053197e-05,0.9825819672131145 -123420000.0,1.0,1.3830406962221326e-05,0.9825819672131146 -123480000.0,1.0,1.3589508480297388e-05,0.9825819672131146 -123540000.0,1.0,1.3352805976029911e-05,0.9825819672131146 -123600000.0,1.0,1.3120226363742503e-05,0.9825819672131146 -123660000.0,1.0,1.289169783076748e-05,0.9825819672131146 -123720000.0,1.0,1.2667149815272553e-05,0.9825819672131146 -123780000.0,1.0,1.2446512984473746e-05,0.9825819672131146 -123840000.0,1.0,1.222971921322779e-05,0.9825819672131147 -123900000.0,1.0,1.2016701562997386e-05,0.9825819672131146 -123960000.0,1.0,1.180739426118288e-05,0.9825819672131145 -124020000.0,1.0,1.1601732680813916e-05,0.9825819672131147 -124080000.0,1.0,1.1399653320594818e-05,0.9825819672131145 -124140000.0,1.0,1.120109378529757e-05,0.9825819672131145 -124200000.0,1.0,1.100599276649628e-05,0.9825819672131146 -124260000.0,1.0,1.0814290023637225e-05,0.9825819672131147 -124320000.0,1.0,1.0625926365438625e-05,0.9825819672131146 -124380000.0,1.0,1.0440843631614386e-05,0.9825819672131146 -124440000.0,1.0,1.0258984674916183e-05,0.9825819672131146 -124500000.0,1.0,1.008029334348834e-05,0.9825819672131147 -124560000.0,1.0,9.90471446353004e-06,0.9825819672131147 -124620000.0,1.0,9.732193822259536e-06,0.9825819672131147 -124680000.0,1.0,9.562678151175097e-06,0.9825819672131146 -124740000.0,1.0,9.396115109607496e-06,0.9825819672131145 -124800000.0,1.0,9.232453268559004e-06,0.9825819672131147 -124860000.0,1.0,9.071642094823856e-06,0.9825819672131145 -124920000.0,1.0,8.913631935385325e-06,0.9825819672131146 -124980000.0,1.0,8.758374002084554e-06,0.9825819672131146 -125040000.0,1.0,8.605820356556442e-06,0.9825819672131146 -125100000.0,1.0,8.455923895427896e-06,0.9825819672131146 -125160000.0,1.0,8.308638335773926e-06,0.9825819672131146 -125220000.0,1.0,8.163918200827042e-06,0.9825819672131145 -125280000.0,1.0,8.021718805935587e-06,0.9825819672131147 -125340000.0,1.0,7.881996244766627e-06,0.9825819672131147 -125400000.0,1.0,7.744707375749175e-06,0.9825819672131147 -125460000.0,1.0,7.609809808753544e-06,0.9825819672131147 -125520000.0,1.0,7.477261892002713e-06,0.9825819672131146 -125580000.0,1.0,7.347022699211681e-06,0.9825819672131146 -125640000.0,1.0,7.219052016950821e-06,0.9825819672131147 -125700000.0,1.0,7.093310332229341e-06,0.9825819672131146 -125760000.0,1.0,6.969758820295018e-06,0.9825819672131146 -125820000.0,1.0,6.848359332646436e-06,0.9825819672131146 -125880000.0,1.0,6.729074385254028e-06,0.9825819672131146 -125940000.0,1.0,6.611867146986283e-06,0.9825819672131146 -126000000.0,1.0,6.496701428237545e-06,0.9825819672131145 -126060000.0,1.0,6.3835416697538985e-06,0.9825819672131146 -126120000.0,1.0,6.2723529316536756e-06,0.9825819672131145 -126180000.0,1.0,6.163100882639216e-06,0.9825819672131147 -126240000.0,1.0,6.055751789396524e-06,0.9825819672131146 -126300000.0,1.0,5.950272506179576e-06,0.9825819672131146 -126360000.0,1.0,5.846630464576037e-06,0.9825819672131146 -126420000.0,1.0,5.744793663451248e-06,0.9825819672131145 -126480000.0,1.0,5.6447306590673635e-06,0.9825819672131146 -126540000.0,1.0,5.546410555374591e-06,0.9825819672131146 -126600000.0,1.0,5.4498029944715496e-06,0.9825819672131146 -126660000.0,1.0,5.354878147231778e-06,0.9825819672131145 -126720000.0,1.0,5.261606704093519e-06,0.9825819672131146 -126780000.0,1.0,5.1699598660099225e-06,0.9825819672131147 -126840000.0,1.0,5.07990933555688e-06,0.9825819672131146 -126900000.0,1.0,4.991427308195745e-06,0.9825819672131145 -126960000.0,1.0,4.904486463688236e-06,0.9825819672131146 -127020000.0,1.0,4.8190599576608785e-06,0.9825819672131145 -127080000.0,1.0,4.735121413316375e-06,0.9825819672131146 -127140000.0,1.0,4.652644913289347e-06,0.9825819672131146 -127200000.0,1.0,4.571604991643938e-06,0.9825819672131146 -127260000.0,1.0,4.491976626010795e-06,0.9825819672131146 -127320000.0,1.0,4.413735229861016e-06,0.9825819672131146 -127380000.0,1.0,4.336856644914666e-06,0.9825819672131146 -127440000.0,1.0,4.2613171336815206e-06,0.9825819672131146 -127500000.0,1.0,4.187093372131739e-06,0.9825819672131146 -127560000.0,1.0,4.114162442494198e-06,0.9825819672131146 -127620000.0,1.0,4.042501826180262e-06,0.9825819672131145 -127680000.0,1.0,3.97208939683081e-06,0.9825819672131147 -127740000.0,1.0,3.9029034134843715e-06,0.9825819672131146 -127800000.0,1.0,3.834922513864253e-06,0.9825819672131145 -127860000.0,1.0,3.768125707782601e-06,0.9825819672131146 -127920000.0,1.0,3.702492370659338e-06,0.9825819672131145 -127980000.0,1.0,3.638002237154001e-06,0.9825819672131147 -128040000.0,1.0,3.5746353949084897e-06,0.9825819672131145 -128100000.0,1.0,3.5123722783988132e-06,0.9825819672131147 -128160000.0,1.0,3.4511936628939156e-06,0.9825819672131146 -128220000.0,1.0,3.391080658519738e-06,0.9825819672131145 -128280000.0,1.0,3.3320147044266683e-06,0.9825819672131145 -128340000.0,1.0,3.2739775630585803e-06,0.9825819672131146 -128400000.0,1.0,3.216951314521699e-06,0.9825819672131146 -128460000.0,1.0,3.160918351051546e-06,0.9825819672131146 -128520000.0,1.0,3.1058613715762627e-06,0.9825819672131146 -128580000.0,1.0,3.0517633763746264e-06,0.9825819672131145 -128640000.0,1.0,2.998607661827117e-06,0.9825819672131146 -128700000.0,1.0,2.946377815258407e-06,0.9825819672131146 -128760000.0,1.0,2.895057709869684e-06,0.9825819672131146 -128820000.0,1.0,2.844631499759249e-06,0.9825819672131146 -128880000.0,1.0,2.7950836150298356e-06,0.9825819672131147 -128940000.0,1.0,2.7463987569811596e-06,0.9825819672131145 -129000000.0,1.0,2.6985618933862005e-06,0.9825819672131146 -129060000.0,1.0,2.65155825384976e-06,0.9825819672131146 -129120000.0,1.0,2.6053733252478687e-06,0.9825819672131146 -129180000.0,1.0,2.559992847246625e-06,0.9825819672131147 -129240000.0,1.0,2.5154028078990914e-06,0.9825819672131146 -129300000.0,1.0,2.4715894393188813e-06,0.9825819672131145 -129360000.0,1.0,2.428539213429105e-06,0.9825819672131145 -129420000.0,1.0,2.3862388377853603e-06,0.9825819672131146 -129480000.0,1.0,2.3446752514714754e-06,0.9825819672131145 -129540000.0,1.0,2.3038356210667464e-06,0.9825819672131146 -129600000.0,1.0,2.2637073366834116e-06,0.9825819672131146 -129660000.0,1.0,2.224278008073147e-06,0.9825819672131147 -129720000.0,1.0,2.185535460801381e-06,0.9825819672131145 -129780000.0,1.0,2.1474677324882417e-06,0.9825819672131146 -129840000.0,1.0,2.110063069114983e-06,0.9825819672131146 -129900000.0,1.0,2.0733099213947423e-06,0.9825819672131146 -129960000.0,1.0,2.0371969412065142e-06,0.9825819672131147 -130020000.0,1.0,2.0017129780912366e-06,0.9825819672131146 -130080000.0,1.0,1.9668470758089094e-06,0.9825819672131146 -130140000.0,1.0,1.93258846895568e-06,0.9825819672131146 -130200000.0,1.0,1.8989265796398537e-06,0.9825819672131146 -130260000.0,1.0,1.8658510142157986e-06,0.9825819672131146 -130320000.0,1.0,1.8333515600747444e-06,0.9825819672131146 -130380000.0,1.0,1.8014181824914751e-06,0.9825819672131146 -130440000.0,1.0,1.770041021525947e-06,0.9825819672131145 -130500000.0,1.0,1.739210388978876e-06,0.9825819672131146 -130560000.0,1.0,1.7089167654003503e-06,0.9825819672131146 -130620000.0,1.0,1.6791507971505488e-06,0.9825819672131145 -130680000.0,1.0,1.6499032935116558e-06,0.9825819672131146 -130740000.0,1.0,1.6211652238500797e-06,0.9825819672131146 -130800000.0,1.0,1.5929277148281007e-06,0.9825819672131146 -130860000.0,1.0,1.5651820476640864e-06,0.9825819672131146 -130920000.0,1.0,1.537919655440429e-06,0.9825819672131146 -130980000.0,1.0,1.5111321204583722e-06,0.9825819672131146 -131040000.0,1.0,1.4848111716389126e-06,0.9825819672131146 -131100000.0,1.0,1.4589486819689724e-06,0.9825819672131146 -131160000.0,1.0,1.4335366659920537e-06,0.9825819672131146 -131220000.0,1.0,1.4085672773426019e-06,0.9825819672131147 -131280000.0,1.0,1.3840328063233146e-06,0.9825819672131146 -131340000.0,1.0,1.3599256775246503e-06,0.9825819672131147 -131400000.0,1.0,1.3362384474857986e-06,0.9825819672131146 -131460000.0,1.0,1.3129638023963942e-06,0.9825819672131146 -131520000.0,1.0,1.2900945558382602e-06,0.9825819672131146 -131580000.0,1.0,1.267623646566487e-06,0.9825819672131145 -131640000.0,1.0,1.2455441363291606e-06,0.9825819672131146 -131700000.0,1.0,1.2238492077250665e-06,0.9825819672131146 -131760000.0,1.0,1.2025321620987076e-06,0.9825819672131146 -131820000.0,1.0,1.1815864174719884e-06,0.9825819672131147 -131880000.0,1.0,1.1610055065119228e-06,0.9825819672131146 -131940000.0,1.0,1.1407830745337438e-06,0.9825819672131147 -132000000.0,1.0,1.120912877538791e-06,0.9825819672131145 -132060000.0,1.0,1.1013887802865785e-06,0.9825819672131147 -132120000.0,1.0,1.0822047544004391e-06,0.9825819672131146 -132180000.0,1.0,1.0633548765061692e-06,0.9825819672131147 -132240000.0,1.0,1.0448333264030902e-06,0.9825819672131145 -132300000.0,1.0,1.0266343852669705e-06,0.9825819672131145 -132360000.0,1.0,1.0087524338842466e-06,0.9825819672131147 -132420000.0,1.0,9.911819509170003e-07,0.9825819672131145 -132480000.0,1.0,9.73917511198159e-07,0.9825819672131145 -132540000.0,1.0,9.569537840563876e-07,0.9825819672131146 -132600000.0,1.0,9.402855316701593e-07,0.9825819672131145 -132660000.0,1.0,9.239076074504945e-07,0.9825819672131146 -132720000.0,1.0,9.078149544518688e-07,0.9825819672131145 -132780000.0,1.0,8.920026038108014e-07,0.9825819672131147 -132840000.0,1.0,8.764656732116378e-07,0.9825819672131146 -132900000.0,1.0,8.61199365379058e-07,0.9825819672131146 -132960000.0,1.0,8.461989665968407e-07,0.9825819672131146 -133020000.0,1.0,8.314598452524284e-07,0.9825819672131146 -133080000.0,1.0,8.169774504068431e-07,0.9825819672131147 -133140000.0,1.0,8.027473103895107e-07,0.9825819672131146 -133200000.0,1.0,7.887650314175621e-07,0.9825819672131146 -133260000.0,1.0,7.750262962391823e-07,0.9825819672131145 -133320000.0,1.0,7.615268628005899e-07,0.9825819672131146 -133380000.0,1.0,7.482625629362353e-07,0.9825819672131146 -133440000.0,1.0,7.352293010818131e-07,0.9825819672131146 -133500000.0,1.0,7.224230530096913e-07,0.9825819672131146 -133560000.0,1.0,7.098398645863665e-07,0.9825819672131145 -133620000.0,1.0,6.974758505515629e-07,0.9825819672131146 -133680000.0,1.0,6.85327193318595e-07,0.9825819672131146 -133740000.0,1.0,6.733901417956277e-07,0.9825819672131147 -133800000.0,1.0,6.61661010227466e-07,0.9825819672131145 -133860000.0,1.0,6.501361770575204e-07,0.9825819672131147 -133920000.0,1.0,6.388120838095922e-07,0.9825819672131146 -133980000.0,1.0,6.276852339891381e-07,0.9825819672131145 -134040000.0,1.0,6.167521920036715e-07,0.9825819672131146 -134100000.0,1.0,6.060095821019682e-07,0.9825819672131146 -134160000.0,1.0,5.954540873317494e-07,0.9825819672131146 -134220000.0,1.0,5.850824485155201e-07,0.9825819672131146 -134280000.0,1.0,5.748914632442456e-07,0.9825819672131146 -134340000.0,1.0,5.648779848885569e-07,0.9825819672131147 -134400000.0,1.0,5.550389216271783e-07,0.9825819672131146 -134460000.0,1.0,5.453712354922786e-07,0.9825819672131146 -134520000.0,1.0,5.358719414314499e-07,0.9825819672131146 -134580000.0,1.0,5.265381063860249e-07,0.9825819672131145 -134640000.0,1.0,5.173668483854486e-07,0.9825819672131147 -134700000.0,1.0,5.083553356574234e-07,0.9825819672131147 -134760000.0,1.0,4.995007857535543e-07,0.9825819672131147 -134820000.0,1.0,4.908004646902239e-07,0.9825819672131145 -134880000.0,1.0,4.82251686104431e-07,0.9825819672131146 -134940000.0,1.0,4.738518104243333e-07,0.9825819672131146 -135000000.0,1.0,4.655982440542373e-07,0.9825819672131146 -135060000.0,1.0,4.574884385737843e-07,0.9825819672131145 -135120000.0,1.0,4.495198899510851e-07,0.9825819672131145 -135180000.0,1.0,4.4169013776956e-07,0.9825819672131145 -135240000.0,1.0,4.3399676446824586e-07,0.9825819672131146 -135300000.0,1.0,4.264373945953358e-07,0.9825819672131146 -135360000.0,1.0,4.1900969407472026e-07,0.9825819672131146 -135420000.0,1.0,4.1171136948530394e-07,0.9825819672131145 -135480000.0,1.0,4.045401673528754e-07,0.9825819672131146 -135540000.0,1.0,3.9749387345431095e-07,0.9825819672131146 -135600000.0,1.0,3.905703121338977e-07,0.9825819672131146 -135660000.0,1.0,3.8376734563156545e-07,0.9825819672131147 -135720000.0,1.0,3.7708287342281887e-07,0.9825819672131146 -135780000.0,1.0,3.7051483157016726e-07,0.9825819672131146 -135840000.0,1.0,3.640611920858508e-07,0.9825819672131146 -135900000.0,1.0,3.577199623056669e-07,0.9825819672131147 -135960000.0,1.0,3.514891842737034e-07,0.9825819672131146 -136020000.0,1.0,3.453669341377884e-07,0.9825819672131146 -136080000.0,1.0,3.3935132155547034e-07,0.9825819672131146 -136140000.0,1.0,3.334404891103443e-07,0.9825819672131146 -136200000.0,1.0,3.276326117385452e-07,0.9825819672131146 -136260000.0,1.0,3.2192589616523036e-07,0.9825819672131147 -136320000.0,1.0,3.1631858035087694e-07,0.9825819672131146 -136380000.0,1.0,3.1080893294722435e-07,0.9825819672131146 -136440000.0,1.0,3.0539525276269277e-07,0.9825819672131147 -136500000.0,1.0,3.000758682371131e-07,0.9825819672131147 -136560000.0,1.0,2.9484913692560596e-07,0.9825819672131146 -136620000.0,1.0,2.897134449914509e-07,0.9825819672131146 -136680000.0,1.0,2.846672067077883e-07,0.9825819672131145 -136740000.0,1.0,2.7970886396800096e-07,0.9825819672131146 -136800000.0,1.0,2.748368858046239e-07,0.9825819672131146 -136860000.0,1.0,2.700497679166335e-07,0.9825819672131147 -136920000.0,1.0,2.653460322049708e-07,0.9825819672131146 -136980000.0,1.0,2.607242263161547e-07,0.9825819672131146 -137040000.0,1.0,2.5618292319384457e-07,0.9825819672131146 -137100000.0,1.0,2.51720720638214e-07,0.9825819672131145 -137160000.0,1.0,2.473362408729992e-07,0.9825819672131145 -137220000.0,1.0,2.430281301200883e-07,0.9825819672131145 -137280000.0,1.0,2.3879505818152113e-07,0.9825819672131146 -137340000.0,1.0,2.3463571802876918e-07,0.9825819672131145 -137400000.0,1.0,2.3054882539916969e-07,0.9825819672131146 -137460000.0,1.0,2.2653311839938902e-07,0.9825819672131145 -137520000.0,1.0,2.2258735711579306e-07,0.9825819672131145 -137580000.0,1.0,2.1871032323160402e-07,0.9825819672131146 -137640000.0,1.0,2.1490081965072563e-07,0.9825819672131145 -137700000.0,1.0,2.1115767012812076e-07,0.9825819672131146 -137760000.0,1.0,2.0750097925286178e-07,0.9826826519110565 -137820000.0,1.0,2.0392850902182252e-07,0.982783357245337 -137880000.0,1.0,2.0043808563280492e-07,0.9828840832223017 -137940000.0,1.0,1.9702759750088145e-07,0.9829848298482986 -138000000.0,1.0,1.9369499334017967e-07,0.9830855971296769 -138060000.0,1.0,1.904382803088295e-07,0.9831863850727905 -138120000.0,1.0,1.8725552221487487e-07,0.9832871936839945 -138180000.0,1.0,1.8414483778103466e-07,0.9833880229696472 -138240000.0,1.0,1.8110439896627242e-07,0.9834888729361091 -138300000.0,1.0,1.781324293422105e-07,0.9835897435897436 -138360000.0,1.0,1.7522720252249447e-07,0.9836906349369164 -138420000.0,1.0,1.7238704064328294e-07,0.9837915469839967 -138480000.0,1.0,1.6961031289310385e-07,0.983892479737355 -138540000.0,1.0,1.668954340903823e-07,0.9839934332033655 -138600000.0,1.0,1.6424086330700527e-07,0.9840944073884044 -138660000.0,1.0,1.6164510253634856e-07,0.9841954022988505 -138720000.0,1.0,1.5910669540424743e-07,0.9842964179410859 -138780000.0,1.0,1.566242259214466e-07,0.9843974543214945 -138840000.0,1.0,1.5419631727611874e-07,0.9844985114464632 -138900000.0,1.0,1.5182163066509022e-07,0.984599589322382 -138960000.0,1.0,1.4949886416246176e-07,0.9847006879556421 -139020000.0,1.0,1.4722675162435902e-07,0.9848018073526391 -139080000.0,1.0,1.4500406162859228e-07,0.98490294751977 -139140000.0,1.0,1.4282959644804849e-07,0.9850041084634347 -139200000.0,1.0,1.4070219105668052e-07,0.9851052901900359 -139260000.0,1.0,1.386207121669988e-07,0.985206492705979 -139320000.0,1.0,1.3658405729800863e-07,0.9853077160176715 -139380000.0,1.0,1.345911538725753e-07,0.9854089601315249 -139440000.0,1.0,1.3264095834323266e-07,0.9855102250539512 -139500000.0,1.0,1.307324553454883e-07,0.9856115107913668 -139560000.0,1.0,1.288646568777092e-07,0.9857128173501902 -139620000.0,1.0,1.2703660150670552e-07,0.9858141447368421 -139680000.0,1.0,1.2524735359816037e-07,0.9859154929577464 -139740000.0,1.0,1.234960025710835e-07,0.9860168620193298 -139800000.0,1.0,1.2178166217549518e-07,0.9861182519280205 -139860000.0,1.0,1.2010346979257493e-07,0.9862196626902507 -139920000.0,1.0,1.1846058575653537e-07,0.9863210943124548 -139980000.0,1.0,1.1685219269750814e-07,0.9864225468010697 -140040000.0,1.0,1.1527749490475291e-07,0.9865240201625347 -140100000.0,1.0,1.137357177095247e-07,0.9866255144032919 -140160000.0,1.0,1.1222610688695772e-07,0.9867270295297871 -140220000.0,1.0,1.1074792807634539e-07,0.9868285655484668 -140280000.0,1.0,1.0930046621921913e-07,0.9869301224657816 -140340000.0,1.0,1.0788302501464712e-07,0.9870317002881843 -140400000.0,1.0,1.0649492639119567e-07,0.9871332990221308 -140460000.0,1.0,1.0513550999501404e-07,0.9872349186740785 -140520000.0,1.0,1.0380413269352256e-07,0.987336559250489 -140580000.0,1.0,1.0250016809420113e-07,0.9874382207578254 -140640000.0,1.0,1.0122300607799288e-07,0.9875399032025538 -140700000.0,1.0,9.997205234685392e-08,0.9876416065911431 -140760000.0,1.0,9.87467279849963e-08,0.9877433309300648 -140820000.0,1.0,9.754646903338632e-08,0.987845076225793 -140880000.0,1.0,9.637072607707578e-08,0.9879468424848046 -140940000.0,1.0,9.521896384495742e-08,0.9880486297135792 -141000000.0,1.0,9.409066082154987e-08,0.9881504379185985 -141060000.0,1.0,9.298530887043108e-08,0.9882522671063478 -141120000.0,1.0,9.190241286895126e-08,0.9883541172833145 -141180000.0,1.0,9.084149035386958e-08,0.9884559884559885 -141240000.0,1.0,8.980207117757027e-08,0.9885578806308628 -141300000.0,1.0,8.878369717452564e-08,0.9886597938144328 -141360000.0,1.0,8.778592183768438e-08,0.9887617280131972 -141420000.0,1.0,8.680831000447446e-08,0.9888636832336565 -141480000.0,1.0,8.585043755212024e-08,0.9889656594823141 -141540000.0,1.0,8.491189110198363e-08,0.9890676567656768 -141600000.0,1.0,8.399226773264807e-08,0.9891696750902528 -141660000.0,1.0,8.309117470147462e-08,0.989271714462554 -141720000.0,1.0,8.220822917436723e-08,0.9893737748890952 -141780000.0,1.0,8.134305796349377e-08,0.9894758563763928 -141840000.0,1.0,8.049529727271749e-08,0.9895779589309668 -141900000.0,1.0,7.966459245050161e-08,0.9896800825593394 -141960000.0,1.0,7.885059775005784e-08,0.9897822272680359 -142020000.0,1.0,7.80529760965168e-08,0.9898843930635838 -142080000.0,1.0,7.727139886090595e-08,0.9899865799525135 -142140000.0,1.0,7.650554564072766e-08,0.9900887879413587 -142200000.0,1.0,7.57551040469363e-08,0.9901910170366545 -142260000.0,1.0,7.501976949712093e-08,0.9902932672449399 -142320000.0,1.0,7.429924501470513e-08,0.9903955385727564 -142380000.0,1.0,7.359324103398287e-08,0.9904978310266475 -142440000.0,1.0,7.290147521081455e-08,0.9906001446131597 -142500000.0,1.0,7.222367223881317e-08,0.9907024793388429 -142560000.0,1.0,7.155956367085632e-08,0.990804835210249 -142620000.0,1.0,7.090888774576483e-08,0.9909072122339325 -142680000.0,1.0,7.027138921999428e-08,0.9910096104164514 -142740000.0,1.0,6.964681920419028e-08,0.9911120297643654 -142800000.0,1.0,6.903493500446354e-08,0.9912144702842377 -142860000.0,1.0,6.843549996824533e-08,0.9913169319826338 -142920000.0,1.0,6.78482833345883e-08,0.9914194148661221 -142980000.0,1.0,6.727306008878224e-08,0.9915219189412737 -143040000.0,1.0,6.670961082115827e-08,0.9916244442146623 -143100000.0,1.0,6.615772158995944e-08,0.9917269906928644 -143160000.0,1.0,6.561718378815917e-08,0.9918295583824595 -143220000.0,1.0,6.50877940141132e-08,0.9919321472900289 -143280000.0,1.0,6.456935394593417e-08,0.9920347574221579 -143340000.0,1.0,6.406167021948154e-08,0.9921373887854333 -143400000.0,1.0,6.35645543098632e-08,0.9922400413864458 -143460000.0,1.0,6.307782241634811e-08,0.9923427152317881 -143520000.0,1.0,6.26012953505928e-08,0.9924454103280553 -143580000.0,1.0,6.213479842808786e-08,0.9925481266818462 -143640000.0,1.0,6.16781613627329e-08,0.992650864299762 -143700000.0,1.0,6.123121816445224e-08,0.9927536231884059 -143760000.0,1.0,6.079380703976569e-08,0.9928564033543843 -143820000.0,1.0,6.036577029523223e-08,0.9929592048043072 -143880000.0,1.0,5.994695424368614e-08,0.9930620275447861 -143940000.0,1.0,5.9537209113188705e-08,0.9931648715824358 -144000000.0,1.0,5.913638895862038e-08,0.9932677369238738 -144060000.0,1.0,5.874435157584103e-08,0.9933706235757197 -144120000.0,1.0,5.836095841834823e-08,0.9934735315445975 -144180000.0,1.0,5.798607451636547e-08,0.9935764608371321 -144240000.0,1.0,5.7619568398294986e-08,0.9936794114599524 -144300000.0,1.0,5.7261312014471385e-08,0.993782383419689 -144360000.0,1.0,5.691118066315479e-08,0.9938853767229765 -144420000.0,1.0,5.656905291870382e-08,0.9939883913764511 -144480000.0,1.0,5.6234810561871007e-08,0.9940914273867524 -144540000.0,1.0,5.590833851216493e-08,0.9941944847605224 -144600000.0,1.0,5.558952476222517e-08,0.9942975635044065 -144660000.0,1.0,5.527826031415796e-08,0.9944006636250519 -144720000.0,1.0,5.4974439117782304e-08,0.9945037851291091 -144780000.0,1.0,5.467795801073763e-08,0.9946069280232316 -144840000.0,1.0,5.4388716660405967e-08,0.9947100923140754 -144900000.0,1.0,5.410661750760303e-08,0.9948132780082988 -144960000.0,1.0,5.38315657119943e-08,0.9949164851125636 -145020000.0,1.0,5.3563469099193324e-08,0.9950197136335337 -145080000.0,1.0,5.330223810950129e-08,0.9951229635778768 -145140000.0,1.0,5.3047785748247955e-08,0.9952262349522623 -145200000.0,1.0,5.280002753769568e-08,0.9953295277633628 -145260000.0,1.0,5.255888147046933e-08,0.9954328420178533 -145320000.0,1.0,5.232426796447637e-08,0.9955361777224125 -145380000.0,1.0,5.209610981928244e-08,0.995639534883721 -145440000.0,1.0,5.1874332173909104e-08,0.9957429135084622 -145500000.0,1.0,5.165886246602163e-08,0.9958463136033229 -145560000.0,1.0,5.1449630392475583e-08,0.9959497351749922 -145620000.0,1.0,5.1246567871192444e-08,0.996053178230162 -145680000.0,1.0,5.1049609004335255e-08,0.9961566427755271 -145740000.0,1.0,5.08586900427566e-08,0.996260128817785 -145800000.0,1.0,5.067374935169203e-08,0.9963636363636362 -145860000.0,1.0,5.049472737767316e-08,0.9964671654197838 -145920000.0,1.0,5.032156661663572e-08,0.9965707159929335 -145980000.0,1.0,5.0154211583198554e-08,0.9966742880897942 -146040000.0,1.0,4.999260878109075e-08,0.9967778817170772 -146100000.0,1.0,4.9836706674704806e-08,0.9968814968814969 -146160000.0,1.0,4.968645566175477e-08,0.9969851335897704 -146220000.0,1.0,4.954180804701894e-08,0.997088791848617 -146280000.0,1.0,4.940271801714792e-08,0.9971924716647602 -146340000.0,1.0,4.926914161651919e-08,0.997296173044925 -146400000.0,1.0,4.914103672412054e-08,0.9973998959958398 -146460000.0,1.0,4.9018363031445386e-08,0.9975036405242355 -146520000.0,1.0,4.8901082021383666e-08,0.9976074066368458 -146580000.0,1.0,4.8789156948092936e-08,0.9977111943404077 -146640000.0,1.0,4.8682552817834904e-08,0.9978150036416606 -146700000.0,1.0,4.8581236370763446e-08,0.9979188345473465 -146760000.0,1.0,4.848517606365089e-08,0.9980226870642105 -146820000.0,1.0,4.839434205353997e-08,0.9981265611990009 -146880000.0,1.0,4.8308706182309606e-08,0.9982304569584679 -146940000.0,1.0,4.822824196214336e-08,0.998334374349365 -147000000.0,1.0,4.8152924561890135e-08,0.9984383133784485 -147060000.0,1.0,4.8082730794307205e-08,0.9985422740524782 -147120000.0,1.0,4.801763910417641e-08,0.9986462563782151 -147180000.0,1.0,4.795762955728513e-08,0.9987502603624245 -147240000.0,1.0,4.790268383026396e-08,0.9988542860118736 -147300000.0,1.0,4.785278520127409e-08,0.9989583333333331 -147360000.0,1.0,4.7807918541537506e-08,0.9990624023335763 -147420000.0,1.0,4.776807030770417e-08,0.9991664930193789 -147480000.0,1.0,4.773322853505085e-08,0.9992706053975201 -147540000.0,1.0,4.770338283150663e-08,0.9993747394747812 -147600000.0,1.0,4.7678524372501155e-08,0.9994788952579469 -147660000.0,1.0,4.765864589663186e-08,0.9995830727538044 -147720000.0,1.0,4.7643741702147346e-08,0.9996872719691441 -147780000.0,1.0,4.763380764424448e-08,0.999791492910759 -147840000.0,1.0,4.762884113317741e-08,0.9998957355854446 -147900000.0,1.0,4.762884113317741e-08,1.0 -147960000.0,1.0,4.762884113317741e-08,1.0 -148020000.0,1.0,4.762884113317741e-08,1.0 -148080000.0,1.0,4.762884113317741e-08,1.0 -148140000.0,1.0,4.762884113317741e-08,1.0 -148200000.0,1.0,4.762884113317741e-08,1.0 -148260000.0,1.0,4.762884113317741e-08,1.0 -148320000.0,1.0,4.762884113317741e-08,1.0 -148380000.0,1.0,4.762884113317741e-08,1.0 -148440000.0,1.0,4.762884113317741e-08,1.0 -148500000.0,1.0,4.762884113317741e-08,1.0 -148560000.0,1.0,4.762884113317741e-08,1.0 -148620000.0,1.0,4.762884113317741e-08,1.0 -148680000.0,1.0,4.762884113317741e-08,1.0 -148740000.0,1.0,4.762884113317741e-08,1.0 -148800000.0,1.0,4.762884113317741e-08,1.0 -148860000.0,1.0,4.762884113317741e-08,1.0 -148920000.0,1.0,4.762884113317741e-08,1.0 -148980000.0,1.0,4.762884113317741e-08,1.0 -149040000.0,1.0,4.762884113317741e-08,1.0 -149100000.0,1.0,4.762884113317741e-08,1.0 -149160000.0,1.0,4.762884113317741e-08,1.0 -149220000.0,1.0,4.762884113317741e-08,1.0 -149280000.0,1.0,4.762884113317741e-08,1.0 -149340000.0,1.0,4.762884113317741e-08,1.0 -149400000.0,1.0,4.762884113317741e-08,1.0 -149460000.0,1.0,4.762884113317741e-08,1.0 -149520000.0,1.0,4.762884113317741e-08,1.0 -149580000.0,1.0,4.762884113317741e-08,1.0 -149640000.0,1.0,4.762884113317741e-08,1.0 -149700000.0,1.0,4.762884113317741e-08,1.0 -149760000.0,1.0,4.762884113317741e-08,1.0 -149820000.0,1.0,4.762884113317741e-08,1.0 -149880000.0,1.0,4.762884113317741e-08,1.0 -149940000.0,1.0,4.762884113317741e-08,1.0 -150000000.0,1.0,4.762884113317741e-08,1.0 -150060000.0,1.0,4.762884113317741e-08,1.0 -150120000.0,1.0,4.762884113317741e-08,1.0 -150180000.0,1.0,4.762884113317741e-08,1.0 -150240000.0,1.0,4.762884113317741e-08,1.0 -150300000.0,1.0,4.762884113317741e-08,1.0 -150360000.0,1.0,4.762884113317741e-08,1.0 -150420000.0,1.0,4.762884113317741e-08,1.0 -150480000.0,1.0,4.762884113317741e-08,1.0 -150540000.0,1.0,4.762884113317741e-08,1.0 -150600000.0,1.0,4.762884113317741e-08,1.0 -150660000.0,1.0,4.762884113317741e-08,1.0 -150720000.0,1.0,4.762884113317741e-08,1.0 -150780000.0,1.0,4.762884113317741e-08,1.0 -150840000.0,1.0,4.762884113317741e-08,1.0 -150900000.0,1.0,4.762884113317741e-08,1.0 -150960000.0,1.0,4.762884113317741e-08,1.0 diff --git a/source-code/Poisson-Graphs/new/outputM.txt b/source-code/Poisson-Graphs/new/outputM.txt deleted file mode 100644 index 99e4ad2..0000000 --- a/source-code/Poisson-Graphs/new/outputM.txt +++ /dev/null @@ -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 diff --git a/source-code/Poisson-Graphs/new/outputM.txt~ b/source-code/Poisson-Graphs/new/outputM.txt~ deleted file mode 100644 index 7af84cc..0000000 --- a/source-code/Poisson-Graphs/new/outputM.txt~ +++ /dev/null @@ -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