def test_negative_gossip_by_zeta(self): Time.use_test_time() Time.set_current_time(1) private_keys = BlockSigners() private_keys = private_keys.block_signers validators = Validators() validators.validators = Validators.read_genesis_validators_from_file() validators.signers_order = [0] + [1] + [2] + [3] + [ 4 ] + [5] * Epoch.get_duration() validators.randomizers_order = [0] * Epoch.get_duration() network = Network() node0 = Node(genesis_creation_time=1, node_id=0, network=network, block_signer=private_keys[0], validators=validators, behaviour=Behaviour()) network.register_node(node0) behavior = Behaviour() # this node malicious skip block behavior.malicious_skip_block = True node1 = Node(genesis_creation_time=1, node_id=1, network=network, block_signer=private_keys[1], validators=validators, behaviour=behavior) network.register_node(node1) node2 = Node(genesis_creation_time=1, node_id=2, network=network, block_signer=private_keys[2], validators=validators, behaviour=Behaviour()) network.register_node(node2) node3 = Node(genesis_creation_time=1, node_id=3, network=network, block_signer=private_keys[3], validators=validators, behaviour=Behaviour()) network.register_node(node3) node4 = Node(genesis_creation_time=1, node_id=4, network=network, block_signer=private_keys[4], validators=validators, behaviour=Behaviour()) network.register_node(node4) node5 = Node(genesis_creation_time=1, node_id=5, network=network, block_signer=private_keys[5], validators=validators, behaviour=Behaviour()) network.register_node(node5) helper = TestHelper(network) Time.advance_to_next_timeslot() # current block number 1 node0.step() # create and sign block node1.step() node2.step() node3.step() node4.step() node5.step() # validate block created and broadcasted helper.list_validator(self, network.nodes, ['dag.blocks_by_number.length'], 2) Time.advance_to_next_timeslot() # current block number 1 node0.step() node1.step() # skip block creation node2.step() node3.step() node4.step() node5.step() # validate block NOT created and NOT broadcasted helper.list_validator(self, network.nodes, ['dag.blocks_by_number.length'], 2) Time.advance_to_next_timeslot() # current block number 2 # for now all chain do not have block from previous timeslot node0.step() # broadcast negative gossip # all nodes handle negative gossips by node0 # not broadcast to self (ADD TO MEMPOOL before broadcast) helper.list_validator(self, network.nodes, ['mempool.gossips.length'], 0) # not permited for gossip send node1.step() # broadcast negative gossip helper.list_validator(self, network.nodes, ['mempool.gossips.length'], 1) node2.step( ) # broadcast negative gossip AND skip block signing for current step !!! node3.step() # broadcast negative gossip node4.step() # broadcast negative gossip node5.step( ) # VALIDATE 5 NEGATIVE GOSSIPS AND DO NOT BROADCAST ANOTHER ONE (current ZETA == 5) # GOSSIPS may be more - see test_negative_gossips_zata_validators helper.list_validator(self, network.nodes, ['mempool.gossips.length'], 5) # duplicate gossips tx will NOT include to mempool ! # if node already send negative gossip IT NOT broadcast it again ! # if node already have x < ZETA (x - different negative gossips by block count) IT NOT broadcast it again ! Time.advance_time(1) # advance time by one second in current timeslot # make steps by nodes node0.step() # node1.step() # # steel 5 negative gossips (from 0,1,2,3,4) on all nodes (add validation ?) helper.list_validator(self, network.nodes, ['mempool.gossips.length'], 5) node2.step( ) # CREATE, SIGN, BROADCAST block (block by node1 not exist) # all nodes handle new block helper.list_validator(self, network.nodes, ['dag.blocks_by_number.length'], 3) # gossips cleaned from mem pool by block handling helper.list_validator(self, network.nodes, ['mempool.gossips.length'], 0) node3.step() # node4.step() # node5.step() # # provide validation for next normal block and FOR GOSSIPS is NOT in mempool after next block Time.advance_to_next_timeslot() # current block number 3 node0.step() # node1.step() # node2.step() # node3.step( ) # must create and sign and broadcast block (all gossips MUST be mined and erased from mempool) node4.step() # node5.step() # # after node2 step helper.list_validator(self, network.nodes, ['dag.blocks_by_number.length'], 4) helper.list_validator(self, network.nodes, ['mempool.gossips.length'], 0)
def test_send_negative_gossip(self): Time.use_test_time() Time.set_current_time(1) private_keys = BlockSigners() private_keys = private_keys.block_signers validators = Validators() validators.validators = Validators.read_genesis_validators_from_file() validators.signers_order = [0, 1] * (Epoch.get_duration() // 2) validators.randomizers_order = [0] * Epoch.get_duration() network = Network() behavior = Behaviour() behavior.malicious_skip_block = True node0 = Node(genesis_creation_time=1, node_id=0, network=network, block_signer=private_keys[0], validators=validators, behaviour=behavior) network.register_node(node0) node1 = Node(genesis_creation_time=1, node_id=1, network=network, block_signer=private_keys[1], validators=validators, behaviour=Behaviour()) network.register_node(node1) Time.advance_to_next_timeslot() node0.step() self.assertEqual(len(node0.dag.blocks_by_number), 1) # ensure that block skipped by node0 node1.step() self.assertEqual(len(node0.dag.blocks_by_number), 1) # ensure that block not received by node1 Time.advance_to_next_timeslot() # on next step node0 broadcast negative gossip node0.step() # and include! it to (node0) self.mempool self.assertEqual(len(node0.mempool.gossips), 1) # assume that negative gossip broadcasted and placed to node1 mempool self.assertEqual(len(node1.mempool.gossips), 1) # ----------------------------------- # on next step node 1 will send negative gossip # node1 MUST create and sign block which contain negative gossip and broadcast it node1.step() # node1 in it's step broadcast(GOSSIP-) and at the same time SKIP!!! method # self.try_to_sign_block(current_block_number) # A second step is needed to create and sign a block within the same time slot Time.advance_time( 1 ) # !!! -----> advance time by 1 second (DO NOT CHANGE TIMESLOT) !!! node1.step() # ----------------------------------- # verify that node1 make block broadcast self.assertEqual(len(node1.dag.blocks_by_number), 2) # verify that node0 receive new block self.assertEqual(len(node0.dag.blocks_by_number), 2) # verify that negative gossip transaction is in block system_txs = node0.dag.blocks_by_number[2][0].block.system_txs self.assertTrue(NegativeGossipTransaction.__class__, system_txs[3].__class__)
def test_send_negative_gossip_by_validator(self): Time.use_test_time() Time.set_current_time(1) private_keys = BlockSigners() private_keys = private_keys.block_signers validators = Validators() validators.validators = Validators.read_genesis_validators_from_file() validators.signers_order = [0] + [1] + [2] * Epoch.get_duration() validators.randomizers_order = [0] * Epoch.get_duration() network = Network() node0 = Node(genesis_creation_time=1, node_id=0, network=network, block_signer=private_keys[0], validators=validators, behaviour=Behaviour()) network.register_node(node0) behavior = Behaviour() behavior.transport_cancel_block_broadcast = True node1 = Node(genesis_creation_time=1, node_id=1, network=network, block_signer=private_keys[1], validators=validators, behaviour=behavior) network.register_node(node1) node2 = Node(genesis_creation_time=1, node_id=2, network=network, block_signer=private_keys[2], validators=validators, behaviour=Behaviour()) network.register_node(node2) # same config from prev. test Time.advance_to_next_timeslot() # current block number 1 node0.step() # create and sign block node1.step() node2.step() self.assertTrue(len(node0.dag.blocks_by_number) == 2, True) self.assertTrue(len(node1.dag.blocks_by_number) == 2, True) self.assertTrue(len(node2.dag.blocks_by_number) == 2, True) # asset that node0 create block number 2 # Time.advance_to_next_timeslot() # current block number 2 node0.step() node1.step() # skip broadcasting block node2.step() self.assertTrue(len(node0.dag.blocks_by_number) == 2, True) self.assertTrue(len(node1.dag.blocks_by_number) == 3, True) self.assertTrue(len(node2.dag.blocks_by_number) == 2, True) # assert that block 3 created on node1 but not broadcasted to node0 and node2 # Time.advance_to_next_timeslot() # current block number 3 node2.step( ) # MAKE FIRST STEP BY CURRENT TIMESLOT VALIDATOR (BLOCK SIGNER) self.assertTrue(len(node0.dag.blocks_by_number) == 3, True) self.assertTrue(len(node1.dag.blocks_by_number) == 3, True) self.assertTrue(len(node2.dag.blocks_by_number) == 3, True) # assert that all listeners nodes receive missed block`s Time.advance_time(1) # ADVANCE TIME BY ONE SECOND TIMESLOT SAME node2.step() self.assertTrue(len(node0.dag.blocks_by_number) == 4, True) self.assertTrue(len(node1.dag.blocks_by_number) == 4, True) self.assertTrue(len(node2.dag.blocks_by_number) == 4, True) # assert that node 2 create, sign, broadcast and deliver block number 4 # for certainty we will make some more steps by NOT VALIDATOR nodes's node0.step() node1.step() node1.step() node0.step() node0.step() Time.advance_to_next_timeslot() # current block number 4 node0.step() node1.step() node2.step() # step by all and validate block 5 self.assertTrue(len(node0.dag.blocks_by_number) == 5, True) self.assertTrue(len(node1.dag.blocks_by_number) == 5, True) self.assertTrue(len(node2.dag.blocks_by_number) == 5, True)
def __init__(self): self.node_to_visualize_after_exit = 0 self.params_validate() self.discrete_mode = True self.malicious_validators_count = GENESIS_VALIDATORS_COUNT / 2 - 1 # set up logging to file - see previous section for more details self.logger = logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)-6s %(name)-6s %(message)s') if self.discrete_mode: Time.use_test_time() Time.set_current_time(BLOCK_TIME) else: Time.set_current_time(int(datetime.datetime.now().timestamp())) self.genesis_creation_time = Time.get_current_time() - BLOCK_TIME # so we start right from the first block self.private_keys = BlockSigners() self.network = Network() self.nodes = [] self.tasks = [] try: # ------------------------------------- # main init section # ------------------------------------- self.launch() # add some extra nodes #self.add_node(10) # ------------------------------------- if self.discrete_mode: should_continue = True terminated_nodes_count = 0 while should_continue: initial_node_count = len(self.nodes) - 1 # one node less because of announcer for node in self.nodes: try: if not node.terminated: node.step() except AssertionError: print("Node", node.node_id, "crashed") self.network.unregister_node(node) node.terminated = True terminated_nodes_count += 1 if terminated_nodes_count == initial_node_count: print("No alive nodes left. Terminating") should_continue = False break Time.advance_time(1) # add some nodes on defined time # will be possible after syncronization mechanism will be implemented) # if Time.get_current_time() == 40: # self.add_node(1) else: self.tasks = [node.run() for node in self.nodes] loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.gather(*self.tasks)) loop.close() finally: if self.node_to_visualize_after_exit: save_dag_to_graphviz(self.node_to_visualize_after_exit.dag) show_node_stats(self.node_to_visualize_after_exit)