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)
Example #4
0
    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)