Changes
This commit is contained in:
parent
c806fc409c
commit
df679e50cb
81
sim.py
81
sim.py
|
@ -1,13 +1,15 @@
|
||||||
# Time between block number increases (NOT time between PoW solutions)
|
# Time between successful PoW solutions
|
||||||
BLOCKTIME = 50
|
POW_SOLUTION_TIME = 10
|
||||||
# Time for a block to traverse the network
|
# Time for a block to traverse the network
|
||||||
TRANSIT_TIME = 50
|
TRANSIT_TIME = 50
|
||||||
# Number of required uncles
|
# Number of required uncles
|
||||||
UNCLES = 4
|
UNCLES = 4
|
||||||
# Uncle block reward (normal block reward = 1)
|
# Uncle block reward (normal block reward = 1)
|
||||||
UNCLE_REWARD_COEFF = 0.875
|
UNCLE_REWARD_COEFF = 0.875
|
||||||
# Block length to test
|
# Reward for including uncles
|
||||||
BLOCKS = 5000
|
NEPHEW_REWARD_COEFF = 0.01
|
||||||
|
# Rounds to test
|
||||||
|
ROUNDS = 80000
|
||||||
|
|
||||||
import random
|
import random
|
||||||
import copy
|
import copy
|
||||||
|
@ -16,7 +18,7 @@ import copy
|
||||||
class Miner():
|
class Miner():
|
||||||
def __init__(self, p):
|
def __init__(self, p):
|
||||||
self.hashpower = p
|
self.hashpower = p
|
||||||
self.id = random.randrange(1000000000)
|
self.id = random.randrange(10000000)
|
||||||
# Set up a few genesis blocks (since the algo is grandpa-dependent,
|
# Set up a few genesis blocks (since the algo is grandpa-dependent,
|
||||||
# we need two genesis blocks plus some genesis uncles)
|
# we need two genesis blocks plus some genesis uncles)
|
||||||
self.blocks = {
|
self.blocks = {
|
||||||
|
@ -25,13 +27,8 @@ class Miner():
|
||||||
1: {"parent": 0, "uncles": [], "miner": -1, "height": 1,
|
1: {"parent": 0, "uncles": [], "miner": -1, "height": 1,
|
||||||
"score": 0, "id": 1, "children": {}}
|
"score": 0, "id": 1, "children": {}}
|
||||||
}
|
}
|
||||||
# for i in range(2, UNCLES + 2):
|
# ID of "latest block"
|
||||||
# self.blocks[i] = {"parent": 0, "uncles": [], "miner": -1,
|
self.head = 1
|
||||||
# "height": 1, "id": i, "children": {}}
|
|
||||||
# ID of parent of "latest block"
|
|
||||||
# We care about the parent of the latest block because that way
|
|
||||||
# we can keep track of uncles.
|
|
||||||
self.head = 0
|
|
||||||
|
|
||||||
# Hear about a block
|
# Hear about a block
|
||||||
def recv(self, block):
|
def recv(self, block):
|
||||||
|
@ -42,29 +39,45 @@ class Miner():
|
||||||
if block["parent"] not in self.blocks:
|
if block["parent"] not in self.blocks:
|
||||||
addme = False
|
addme = False
|
||||||
for u in block["uncles"]:
|
for u in block["uncles"]:
|
||||||
if self.blocks[u]["id"] not in self.blocks:
|
if u not in self.blocks:
|
||||||
addme = False
|
addme = False
|
||||||
p = self.blocks[block["parent"]]
|
p = self.blocks[block["parent"]]
|
||||||
if addme:
|
if addme:
|
||||||
self.blocks[block["id"]] = copy.deepcopy(block)
|
self.blocks[block["id"]] = copy.deepcopy(block)
|
||||||
# Check if the new block's parent deserves to be the new head
|
# Each parent keeps track of its children, to help
|
||||||
|
# facilitate the rule that a block must have N+ siblings
|
||||||
|
# to be valid
|
||||||
if block["id"] not in p["children"]:
|
if block["id"] not in p["children"]:
|
||||||
p["children"][block["id"]] = block["id"]
|
p["children"][block["id"]] = block["id"]
|
||||||
|
# Check if the new block deserves to be the new head
|
||||||
if len(p["children"]) >= 1 + UNCLES:
|
if len(p["children"]) >= 1 + UNCLES:
|
||||||
if block["score"] > self.blocks[self.head]["score"]:
|
if block["score"] > self.blocks[self.head]["score"]:
|
||||||
self.head = block["parent"]
|
self.head = block["id"]
|
||||||
|
|
||||||
# Mine a block
|
# Mine a block
|
||||||
def mine(self):
|
def mine(self):
|
||||||
h = self.blocks[self.head]
|
h = self.blocks[self.blocks[self.head]["parent"]]
|
||||||
b = sorted(list(h["children"]), key=lambda x: self.blocks[x]["id"])
|
b = sorted(list(h["children"]), key=lambda x: -self.blocks[x]["score"])
|
||||||
p = self.blocks[b[0]]
|
p = self.blocks[b[0]]
|
||||||
block = {"parent": b[0], "uncles": b[1:], "miner": self.id,
|
block = {"parent": b[0], "uncles": b[1:], "miner": self.id,
|
||||||
"height": h["height"] + 2, "score": p["score"] + len(b),
|
"height": h["height"] + 2, "score": p["score"] + len(b),
|
||||||
"id": random.randrange(1000000000), "children": {}}
|
"id": random.randrange(1000000000000), "children": {}}
|
||||||
self.recv(block)
|
self.recv(block)
|
||||||
return block
|
return block
|
||||||
|
|
||||||
|
|
||||||
|
def cousin_degree(miner, b1, b2):
|
||||||
|
while miner.blocks[b1]["height"] > miner.blocks[b2]["height"]:
|
||||||
|
b1 = miner.blocks[b1]["parent"]
|
||||||
|
while miner.blocks[b2]["height"] > miner.blocks[b1]["height"]:
|
||||||
|
b2 = miner.blocks[b2]["parent"]
|
||||||
|
t = 0
|
||||||
|
while b1 != b2:
|
||||||
|
b1 = miner.blocks[b1]["parent"]
|
||||||
|
b2 = miner.blocks[b2]["parent"]
|
||||||
|
t += 1
|
||||||
|
return t
|
||||||
|
|
||||||
percentages = [1]*25 + [5, 5, 5, 5, 5, 10, 15, 25]
|
percentages = [1]*25 + [5, 5, 5, 5, 5, 10, 15, 25]
|
||||||
miners = []
|
miners = []
|
||||||
for p in percentages:
|
for p in percentages:
|
||||||
|
@ -76,12 +89,12 @@ for m in miners:
|
||||||
|
|
||||||
listen_queue = []
|
listen_queue = []
|
||||||
|
|
||||||
for t in range(BLOCKS * BLOCKTIME):
|
for t in range(ROUNDS):
|
||||||
if t % 5000 == 0:
|
if t % 5000 == 0:
|
||||||
print t
|
print t
|
||||||
for m in miners:
|
for m in miners:
|
||||||
R = random.randrange(BLOCKTIME * sum(percentages) / (UNCLES + 1))
|
R = random.randrange(POW_SOLUTION_TIME * sum(percentages))
|
||||||
if R < m.hashpower:
|
if R < m.hashpower and t < ROUNDS - TRANSIT_TIME * 3:
|
||||||
b = m.mine()
|
b = m.mine()
|
||||||
listen_queue.append([t + TRANSIT_TIME, b])
|
listen_queue.append([t + TRANSIT_TIME, b])
|
||||||
while len(listen_queue) and listen_queue[0][0] <= t:
|
while len(listen_queue) and listen_queue[0][0] <= t:
|
||||||
|
@ -91,22 +104,36 @@ for t in range(BLOCKS * BLOCKTIME):
|
||||||
|
|
||||||
h = miners[0].blocks[miners[0].head]
|
h = miners[0].blocks[miners[0].head]
|
||||||
profit = {}
|
profit = {}
|
||||||
|
total_blocks_in_chain = 0
|
||||||
|
length_of_chain = 0
|
||||||
|
ZORO = {}
|
||||||
print "### PRINTING BLOCKCHAIN ###"
|
print "### PRINTING BLOCKCHAIN ###"
|
||||||
|
|
||||||
while h["id"] > 1:
|
while h["id"] > 1:
|
||||||
print h["miner"], h["height"], h["score"]
|
print h["miner"], h["height"], h["score"]
|
||||||
profit[h["miner"]] = profit.get(h["miner"], 0) + 1
|
total_blocks_in_chain += 1 + len(h["uncles"])
|
||||||
|
ZORO[h["id"]] = True
|
||||||
|
length_of_chain += 1
|
||||||
|
profit[h["miner"]] = profit.get(h["miner"], 0) + \
|
||||||
|
1 + NEPHEW_REWARD_COEFF * len(h["uncles"])
|
||||||
for u in h["uncles"]:
|
for u in h["uncles"]:
|
||||||
|
ZORO[u] = True
|
||||||
u2 = miners[0].blocks[u]
|
u2 = miners[0].blocks[u]
|
||||||
profit[u2["miner"]] = profit.get(u2["miner"], 0) + UNCLE_REWARD_COEFF
|
profit[u2["miner"]] = profit.get(u2["miner"], 0) + UNCLE_REWARD_COEFF
|
||||||
h = miners[0].blocks[h["parent"]]
|
h = miners[0].blocks[h["parent"]]
|
||||||
|
|
||||||
|
print "### PRINTING HEADS ###"
|
||||||
|
|
||||||
|
for m in miners:
|
||||||
|
print m.head
|
||||||
|
|
||||||
|
|
||||||
print "### PRINTING PROFITS ###"
|
print "### PRINTING PROFITS ###"
|
||||||
|
|
||||||
for p in profit:
|
for p in profit:
|
||||||
print miner_dict[p].hashpower, profit[p]
|
print miner_dict[p].hashpower, profit[p]
|
||||||
|
|
||||||
print "### PRINTING GROUPINGS ###"
|
print "### PRINTING RESULTS ###"
|
||||||
|
|
||||||
groupings = {}
|
groupings = {}
|
||||||
counts = {}
|
counts = {}
|
||||||
|
@ -117,3 +144,11 @@ for p in profit:
|
||||||
|
|
||||||
for c in counts:
|
for c in counts:
|
||||||
print c, groupings[c] / counts[c] / (groupings[1] / counts[1])
|
print c, groupings[c] / counts[c] / (groupings[1] / counts[1])
|
||||||
|
|
||||||
|
print " "
|
||||||
|
print "Total blocks produced: ", len(miners[0].blocks) - 2
|
||||||
|
print "Total blocks in chain: ", total_blocks_in_chain
|
||||||
|
print "Efficiency: ", total_blocks_in_chain * 1.0 / (len(miners[0].blocks) - 2)
|
||||||
|
print "Average uncles: ", total_blocks_in_chain * 1.0 / length_of_chain
|
||||||
|
print "Length of chain: ", length_of_chain
|
||||||
|
print "Block time: ", ROUNDS * 1.0 / length_of_chain
|
||||||
|
|
Loading…
Reference in New Issue