def test_successive_joining(): # bootstrap scenario # this works without repeated VoteNil sending, as the first node will # eventually collect a valid Lockset. # if: # nodes can request proposals, they missed # the network is not disjoint at the beginning # solution: # send current and last valid lockset and proposal with status network = Network(num_nodes=10, simenv=True) # disable nodes, i.e. they won't connect yet for n in network.nodes: n.isactive = False for n in network.nodes: n.isactive = True network.connect_nodes() network.start() network.run(2) network.run(2) r = network.check_consistency() assert_heightdistance(r)
def test_failing_validators(): network = Network(num_nodes=10, simenv=True) network.connect_nodes() network.normvariate_base_latencies() network.disable_validators(num=3) network.start() network.run(10) r = network.check_consistency() assert_heightdistance(r)
def test_slow_validators(): network = Network(num_nodes=10, simenv=True) network.connect_nodes() network.normvariate_base_latencies() network.throttle_validators(num=3) network.start() network.run(5) r = network.check_consistency() assert_heightdistance(r, 1)
def test_basic_gevent(): network = Network(num_nodes=10) network.connect_nodes() network.normvariate_base_latencies() network.start() network.run(10) r = network.check_consistency() assert_maxrounds(r) assert_heightdistance(r)
def test_basic_gevent(): network = Network(num_nodes=4) network.connect_nodes() network.normvariate_base_latencies() network.start() network.run(6) r = network.check_consistency() # note gevent depends on real clock, therefore results are not predictable assert_maxrounds(r) assert_heightdistance(r)
def test_basic_singlenode(): network = Network(num_nodes=1, simenv=True) network.connect_nodes() network.normvariate_base_latencies() network.start() network.run(5) r = network.check_consistency() assert_maxrounds(r) assert_heightdistance(r) assert_blocktime(r, 1.5)
def test_basic_simenv(): network = Network(num_nodes=4, simenv=True) network.connect_nodes() network.normvariate_base_latencies() network.start() network.run(5) r = network.check_consistency() assert_maxrounds(r) assert_heightdistance(r) assert_blocktime(r, 0.5)
def test_low_timeout(monkeypatch): monkeypatch(ConsensusManager, 'round_timeout', 0.1) network = Network(num_nodes=10, simenv=True) network.connect_nodes() network.normvariate_base_latencies() network.start() network.run(5) r = network.check_consistency() assert_heightdistance(r)
def test_low_timeout(): orig_timeout = ConsensusManager.round_timeout ConsensusManager.round_timeout = 0.1 network = Network(num_nodes=10, simenv=True) network.connect_nodes() network.normvariate_base_latencies() network.start() network.run(5) ConsensusManager.round_timeout = orig_timeout r = network.check_consistency() assert_heightdistance(r)
def test_resyncing_of_peers(): network = Network(num_nodes=10, simenv=True) # disable one node, i.e. it will not connect yet network.nodes[0].isactive = False network.connect_nodes() network.normvariate_base_latencies() network.start() network.run(5) network.nodes[0].isactive = True network.connect_nodes() network.normvariate_base_latencies() network.start() network.run(3) r = network.check_consistency() assert_heightdistance(r)
def test_transactions(): sim_time = 5 num_txs = 2 _num_initial_blocks_orig = ConsensusManager.num_initial_blocks num_initial_blocks = 2 ConsensusManager.num_initial_blocks = num_initial_blocks network = Network(num_nodes=4, simenv=True) network.connect_nodes() network.normvariate_base_latencies() app = network.nodes[0] chainservice = app.services.chainservice def cb(blk): log.DEV('ON NEW HEAD', blk=blk) if blk.number >= num_initial_blocks and blk.number < num_initial_blocks + num_txs: if blk.number > num_initial_blocks: assert blk.num_transactions() == 1 sender = chainservice.chain.coinbase to = 'x' * 20 nonce = chainservice.chain.head.get_nonce(sender) log.DEV('CREATING TX', nonce=nonce) gas = 21000 gasprice = 1 value = 1 assert chainservice.chain.head.get_balance(sender) > gas * gasprice + value tx = Transaction(nonce, gasprice, gas, to, value, data='') app.services.accounts.sign_tx(sender, tx) assert tx.sender == sender success = chainservice.add_transaction(tx) chainservice.on_new_head_cbs.append(cb) network.start() network.run(sim_time) r = network.check_consistency() print r expected_head_number = num_initial_blocks + num_txs assert chainservice.chain.head.number == expected_head_number assert_maxrounds(r) assert_heightdistance(r, max_distance=1) assert_blocktime(r, 1.5) # set to old value ConsensusManager.num_initial_blocks = _num_initial_blocks_orig
def test_broadcasting(): network = Network(num_nodes=10, simenv=True) orig_timeout = ConsensusManager.round_timeout # ConsensusManager.round_timeout = 100 # don't trigger timeouts # connect nodes as a ring for i, n in enumerate(network.nodes): if i + 1 < len(network.nodes): o = network.nodes[i + 1] else: o = network.nodes[0] n.connect_app(o) network.normvariate_base_latencies() network.start() network.run(10) ConsensusManager.round_timeout = orig_timeout r = network.check_consistency() assert_maxrounds(r) assert_heightdistance(r)
def test_transactions(monkeypatch): sim_time = 10 num_txs = 2 num_initial_blocks = 2 monkeypatch.setattr(ConsensusManager, 'num_initial_blocks', num_initial_blocks) network = Network(num_nodes=4, simenv=False) network.connect_nodes() network.normvariate_base_latencies() app = network.nodes[0] chainservice = app.services.chainservice # track txs txs = [] def cb(blk): log.DEV('ON NEW HEAD', blk=blk) if num_initial_blocks <= blk.number < num_initial_blocks + num_txs: if blk.number > num_initial_blocks: assert blk.num_transactions() == 1 sender = chainservice.chain.coinbase to = 'x' * 20 nonce = chainservice.chain.head.get_nonce(sender) log.DEV('CREATING TX', nonce=nonce) gas = 21000 gasprice = 1 value = 1 assert chainservice.chain.head.get_balance( sender) > gas * gasprice + value tx = Transaction(nonce, gasprice, gas, to, value, data='') app.services.accounts.sign_tx(sender, tx) assert tx.sender == sender def _do(): log.DEV('ADDING TX', nonce=nonce) success = chainservice.add_transaction(tx) assert success log.DEV('ADDED TX', success=success) if network.simenv: network.simenv.process(_do()) else: gevent.spawn(_do) txs.append(tx) print(chainservice.on_new_head_cbs) chainservice.on_new_head_cbs.append(cb) network.start() network.run(sim_time) r = network.check_consistency() log.debug(r) expected_head_number = num_initial_blocks + num_txs assert chainservice.chain.head.number == expected_head_number assert_maxrounds(r) assert_heightdistance(r, max_distance=1) #assert_blocktime(r, 1.5) # check if all txs are received in all chains tx_pos = set() for app in network.nodes: for tx in txs: r = app.services.chainservice.chain.index.get_transaction(tx.hash) assert len(r) == 3 t, blk, idx = r assert tx == t tx_pos.add(r) assert len(tx_pos) == len(txs)
def test_late_joins(validators, late, delay): """In this test, we spawn a network with a number of `validators` validator nodes, where a number of `late` nodes stay offline until after a certain delay: >>> initial sync_time = delay * (validators - late) Now the "late-joiners" come online and we let them sync until the networks head block is at `num_initial_blocks` (default: 10). Since in some configurations the late-joiners don't manage to catch up at that point, we inject a transaction (leading to a new block) into the now fully online network. Now all nodes must be at the same block-height: `(num_initial_blocks + 1)`. """ network = Network(num_nodes=validators, simenv=True) for node in network.nodes[validators - late:]: node.isactive = False network.connect_nodes() network.normvariate_base_latencies() network.start() network.run(delay * (validators - late)) for node in network.nodes[validators - late:]: node.isactive = True network.connect_nodes() network.normvariate_base_latencies() network.start() network.run(max(10, validators * delay)) r = network.check_consistency() # now majority must be at block 10 # late-joiners may be at block 9 or even still at block 0 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) assert r['heights'][11] == validators