# Path: hydrachain/consensus/simulation.py
# class Network(object):
# 
#     starttime = None
# 
#     def __init__(self, num_nodes=2, simenv=None):
#         if simenv:
#             self.simenv = simpy.Environment()
#         else:
#             self.simenv = None
#         privkeys = mk_privkeys(num_nodes)
#         validators = [privtoaddr(p) for p in privkeys]
#         self.nodes = []
#         for i in range(num_nodes):
#             app = AppMock(privkeys[i], validators, self.simenv)
#             self.nodes.append(app)
# 
#     def connect_nodes(self):
#         # connect nodes
#         for i, n in enumerate(self.nodes):
#             for o in self.nodes[i + 1:]:
#                 if n.isactive and o.isactive:
#                     n.connect_app(o)
# 
#     def start(self):
#         # start nodes
#         for n in self.nodes:
#             if n.isactive:
#                 cm = n.services.chainservice.consensus_manager
#                 if True or self.simenv:   # set dummy ready!"
#                     cm.ready_validators = set(range(int(len(cm.contract.validators))))
#                     assert cm.is_ready
#                 cm.process()
# 
#     def run(self, duration):
#         if self.simenv:
#             self.simenv.run(until=self.elapsed + duration)
#         else:
#             if not self.starttime:
#                 self.starttime = time.time()
#             gevent.sleep(duration)
# 
#     @property
#     def elapsed(self):
#         if self.simenv:
#             return self.simenv.now
#         else:
#             return time.time() - self.starttime
# 
#     def disable_validators(self, num):
#         assert num <= len(self.nodes)
#         for i in range(num):
#             n = self.nodes[i]
#             for p in n.services.peermanager.peers:
#                 p.transport = NoTransport(self.simenv)
# 
#     def throttle_validators(self, num):
#         assert num <= len(self.nodes)
#         for i in reversed(range(num)):
#             n = self.nodes[i]
#             for p in n.services.peermanager.peers:
#                 p.transport = SlowTransport(self.simenv)
# 
#     def normvariate_base_latencies(self, sigma_factor=0.5, base_latency=None):
#         min_latency = 0.001
#         for n in self.nodes:
#             for p in n.services.peermanager.peers:
#                 p.base_latency = base_latency or p.base_latency
#                 sigma = p.base_latency * sigma_factor
#                 p.base_latency = max(min_latency, random.normalvariate(p.base_latency, sigma))
#                 assert p.base_latency > 0
# 
#     def consensus_managers(self):
#         return [n.services.chainservice.consensus_manager for n in self.nodes]
# 
#     def check_consistency(self):
#         if self.simenv:
#             elapsed = self.simenv.now
#         else:
#             elapsed = time.time() - self.starttime
#         cs = self.consensus_managers()
#         # check they are all on the same block or the previous one
#         heights = Counter(c.chain.head.number for c in cs)
#         height_distance = max(heights.keys()) - min(heights.keys())
#         max_height = height = max(heights)
# 
#         # check they are all using the same block
#         while height > 0:
#             bs = list(set(c.chain.index.get_block_by_number(height) for c in cs
#                           if c.chain.index.has_block_by_number(height)))
#             assert len(bs) == 1 or (len(bs) == 2 and None in bs), bs
#             height -= 1
# 
#         # highest round seen (i.e. number of failed proposers)
#         max_rounds = 0
#         for c in cs:
#             blk = c.chain.head
#             while blk.number > 0:
#                 p = c.load_proposal(blk.hash)
#                 max_rounds = max(max_rounds, p.signing_lockset.round)
#                 bh = c.chain.index.get_block_by_number(blk.number - 1)
#                 blk = c.chain.get(bh)
#                 assert isinstance(blk, Block)
#         max_rounds += 1
# 
#         # messages
#         ingress_bytes_transfered = 0
#         egress_bytes_transfered = 0
# 
#         for n in self.nodes:
#             for p in n.services.peermanager.peers:
#                 ingress_bytes_transfered += p.ingress_bytes
#                 egress_bytes_transfered += p.egress_bytes
# 
#         r = dict(max_height=max_height,
#                  max_rounds=max_rounds,
#                  heights=heights,
#                  ingress_bytes_transfered=ingress_bytes_transfered,
#                  egress_bytes_transfered=egress_bytes_transfered,
#                  elapsed=elapsed,
#                  height_distance=height_distance)
#         log.debug('checked consistency', r=r)
#         return r
# 
# def assert_heightdistance(r, max_distance=0):
#     assert r['max_height'] > 0
#     assert r['height_distance'] <= max_distance


import pytest
from hydrachain.consensus.simulation import Network, assert_heightdistance
from ethereum.transactions import Transaction
    assert_heightdistance(r, max_distance=10)
    assert r['heights'][10] >= (validators - late)

    # after a new block, all nodes should be up-to-date:
    chainservice = network.nodes[0].services.chainservice

    sender = chainservice.chain.coinbase
    to = 'x' * 20
    nonce = chainservice.chain.head.get_nonce(sender)
    gas = 21000
    gasprice = 1
    value = 1
    assert chainservice.chain.head.get_balance(sender) > gas * gasprice + value
    tx = Transaction(nonce, gasprice, gas, to, value, data='')
    network.nodes[0].services.accounts.sign_tx(sender, tx)
    assert tx.sender == sender

    success = chainservice.add_transaction(tx)
    assert success

    # run in ever longer bursts until we're at height 11
    for i in range(1, 10):
        network.connect_nodes()
        network.normvariate_base_latencies()
        network.start()
        network.run(2 * i)
        r = network.check_consistency()
        if r['heights'][11] == validators:
            break


# Path: hydrachain/consensus/simulation.py
# class Network(object):
# 
#     starttime = None
# 
#     def __init__(self, num_nodes=2, simenv=None):
#         if simenv:
#             self.simenv = simpy.Environment()
#         else:
#             self.simenv = None
#         privkeys = mk_privkeys(num_nodes)
#         validators = [privtoaddr(p) for p in privkeys]
#         self.nodes = []
#         for i in range(num_nodes):
#             app = AppMock(privkeys[i], validators, self.simenv)
#             self.nodes.append(app)
# 
#     def connect_nodes(self):
#         # connect nodes
#         for i, n in enumerate(self.nodes):
#             for o in self.nodes[i + 1:]:
#                 if n.isactive and o.isactive:
#                     n.connect_app(o)
# 
#     def start(self):
#         # start nodes
#         for n in self.nodes:
#             if n.isactive:
#                 cm = n.services.chainservice.consensus_manager
#                 if True or self.simenv:   # set dummy ready!"
#                     cm.ready_validators = set(range(int(len(cm.contract.validators))))
#                     assert cm.is_ready
#                 cm.process()
# 
#     def run(self, duration):
#         if self.simenv:
#             self.simenv.run(until=self.elapsed + duration)
#         else:
#             if not self.starttime:
#                 self.starttime = time.time()
#             gevent.sleep(duration)
# 
#     @property
#     def elapsed(self):
#         if self.simenv:
#             return self.simenv.now
#         else:
#             return time.time() - self.starttime
# 
#     def disable_validators(self, num):
#         assert num <= len(self.nodes)
#         for i in range(num):
#             n = self.nodes[i]
#             for p in n.services.peermanager.peers:
#                 p.transport = NoTransport(self.simenv)
# 
#     def throttle_validators(self, num):
#         assert num <= len(self.nodes)
#         for i in reversed(range(num)):
#             n = self.nodes[i]
#             for p in n.services.peermanager.peers:
#                 p.transport = SlowTransport(self.simenv)
# 
#     def normvariate_base_latencies(self, sigma_factor=0.5, base_latency=None):
#         min_latency = 0.001
#         for n in self.nodes:
#             for p in n.services.peermanager.peers:
#                 p.base_latency = base_latency or p.base_latency
#                 sigma = p.base_latency * sigma_factor
#                 p.base_latency = max(min_latency, random.normalvariate(p.base_latency, sigma))
#                 assert p.base_latency > 0
# 
#     def consensus_managers(self):
#         return [n.services.chainservice.consensus_manager for n in self.nodes]
# 
#     def check_consistency(self):
#         if self.simenv:
#             elapsed = self.simenv.now
#         else:
#             elapsed = time.time() - self.starttime
#         cs = self.consensus_managers()
#         # check they are all on the same block or the previous one
#         heights = Counter(c.chain.head.number for c in cs)
#         height_distance = max(heights.keys()) - min(heights.keys())
#         max_height = height = max(heights)
# 
#         # check they are all using the same block
#         while height > 0:
#             bs = list(set(c.chain.index.get_block_by_number(height) for c in cs
#                           if c.chain.index.has_block_by_number(height)))
#             assert len(bs) == 1 or (len(bs) == 2 and None in bs), bs
#             height -= 1
# 
#         # highest round seen (i.e. number of failed proposers)
#         max_rounds = 0
#         for c in cs:
#             blk = c.chain.head
#             while blk.number > 0:
#                 p = c.load_proposal(blk.hash)
#                 max_rounds = max(max_rounds, p.signing_lockset.round)
#                 bh = c.chain.index.get_block_by_number(blk.number - 1)
#                 blk = c.chain.get(bh)
#                 assert isinstance(blk, Block)
#         max_rounds += 1
# 
#         # messages
#         ingress_bytes_transfered = 0
#         egress_bytes_transfered = 0
# 
#         for n in self.nodes:
#             for p in n.services.peermanager.peers:
#                 ingress_bytes_transfered += p.ingress_bytes
#                 egress_bytes_transfered += p.egress_bytes
# 
#         r = dict(max_height=max_height,
#                  max_rounds=max_rounds,
#                  heights=heights,
#                  ingress_bytes_transfered=ingress_bytes_transfered,
#                  egress_bytes_transfered=egress_bytes_transfered,
#                  elapsed=elapsed,
#                  height_distance=height_distance)
#         log.debug('checked consistency', r=r)
#         return r
# 
# def assert_heightdistance(r, max_distance=0):
#     assert r['max_height'] > 0
#     assert r['height_distance'] <= max_distance


# Path: hydrachain/tests/test_sim_joins.py
import pytest
from hydrachain.consensus.simulation import Network, assert_heightdistance
from ethereum.transactions import Transaction

    assert_heightdistance(r, max_distance=10)
    assert r['heights'][10] >= (validators - late)

    # after a new block, all nodes should be up-to-date:
    chainservice = network.nodes[0].services.chainservice

    sender = chainservice.chain.coinbase
    to = 'x' * 20
    nonce = chainservice.chain.head.get_nonce(sender)
    gas = 21000
    gasprice = 1
    value = 1
    assert chainservice.chain.head.get_balance(sender) > gas * gasprice + value
    tx = Transaction(nonce, gasprice, gas, to, value, data='')
    network.nodes[0].services.accounts.sign_tx(sender, tx)
    assert tx.sender == sender

    success = chainservice.add_transaction(tx)
    assert success

    # run in ever longer bursts until we're at height 11
    for i in range(1, 10):
        network.connect_nodes()
        network.normvariate_base_latencies()
        network.start()
        network.run(2 * i)
        r = network.check_consistency()
        if r['heights'][11] == validators:
            break


    assert_heightdistance(r)