def test_top_blocks(self):
        dag = Dag(0)
        epoch = Epoch(dag)
        private = Private.generate()

        epoch_hash = dag.genesis_block().get_hash()

        self.assertEqual(dag.genesis_block().get_hash(),
                         list(epoch.get_epoch_hashes().keys())[0])
        self.assertEqual(dag.genesis_block().get_hash(),
                         list(epoch.get_epoch_hashes().values())[0])

        block1 = BlockFactory.create_block_with_timestamp(
            [dag.genesis_block().get_hash()], BLOCK_TIME)
        signed_block1 = BlockFactory.sign_block(block1, private)
        dag.add_signed_block(1, signed_block1)

        self.assertEqual(block1.get_hash(),
                         list(epoch.get_epoch_hashes().keys())[0])
        self.assertEqual(epoch_hash,
                         list(epoch.get_epoch_hashes().values())[0])

        prev_hash = block1.get_hash()
        epoch_length = ROUND_DURATION * 6 + 1
        for i in range(2, epoch_length + 1):
            block = BlockFactory.create_block_with_timestamp([prev_hash],
                                                             BLOCK_TIME * i)
            signed_block = BlockFactory.sign_block(block, private)
            dag.add_signed_block(i, signed_block)
            prev_hash = block.get_hash()

        if epoch.is_new_epoch_upcoming(epoch_length + 1):
            epoch.accept_tops_as_epoch_hashes()

        top_block_hash = dag.blocks_by_number[epoch_length][0].get_hash()
        epoch_hash = dag.blocks_by_number[epoch_length][0].get_hash()

        self.assertEqual(top_block_hash,
                         list(epoch.get_epoch_hashes().keys())[0])
        self.assertEqual(epoch_hash,
                         list(epoch.get_epoch_hashes().values())[0])

        epoch2 = epoch_length * 2 + 1
        for i in range(epoch_length + 1, epoch2):
            block = BlockFactory.create_block_with_timestamp([prev_hash],
                                                             BLOCK_TIME * i)
            signed_block = BlockFactory.sign_block(block, private)
            dag.add_signed_block(i, signed_block)
            prev_hash = block.get_hash()

        if epoch.is_new_epoch_upcoming(epoch2):
            epoch.accept_tops_as_epoch_hashes()

        top_block_hash = dag.blocks_by_number[epoch2 - 1][0].get_hash()
        epoch_hash = dag.blocks_by_number[epoch2 - 1][0].get_hash()

        self.assertEqual(top_block_hash,
                         list(epoch.get_epoch_hashes().keys())[0])
        self.assertEqual(epoch_hash,
                         list(epoch.get_epoch_hashes().values())[0])
Beispiel #2
0
    def test_chain_length(self):
        dag = Dag(0)
        private = Private.generate()
        block1 = BlockFactory.create_block_with_timestamp(
            [dag.genesis_block().get_hash()], BLOCK_TIME)
        signed_block1 = BlockFactory.sign_block(block1, private)
        dag.add_signed_block(1, signed_block1)

        block2 = BlockFactory.create_block_with_timestamp([block1.get_hash()],
                                                          BLOCK_TIME * 2)
        signed_block2 = BlockFactory.sign_block(block2, private)
        dag.add_signed_block(2, signed_block2)

        block3 = BlockFactory.create_block_with_timestamp([block2.get_hash()],
                                                          BLOCK_TIME * 3)
        signed_block3 = BlockFactory.sign_block(block3, private)
        dag.add_signed_block(3, signed_block3)

        # alternative chain
        other_block2 = BlockFactory.create_block_with_timestamp(
            [block1.get_hash()], BLOCK_TIME * 2 + 1)
        other_signed_block2 = BlockFactory.sign_block(other_block2, private)
        dag.add_signed_block(2, other_signed_block2)

        self.assertEqual(
            dag.calculate_chain_length(other_block2.get_hash(),
                                       dag.genesis_hash()), 3)
        self.assertEqual(
            dag.calculate_chain_length(block3.get_hash(), dag.genesis_hash()),
            4)
Beispiel #3
0
    def test_ancestry(self):
        dag = Dag(0)
        private = Private.generate()
        block1 = BlockFactory.create_block_with_timestamp(
            [dag.genesis_block().get_hash()], BLOCK_TIME)
        signed_block1 = BlockFactory.sign_block(block1, private)
        dag.add_signed_block(1, signed_block1)

        block2 = BlockFactory.create_block_with_timestamp([block1.get_hash()],
                                                          BLOCK_TIME * 2)
        signed_block2 = BlockFactory.sign_block(block2, private)
        dag.add_signed_block(2, signed_block2)

        block3 = BlockFactory.create_block_with_timestamp([block2.get_hash()],
                                                          BLOCK_TIME * 3)
        signed_block3 = BlockFactory.sign_block(block3, private)
        dag.add_signed_block(3, signed_block3)

        # alternative chain
        other_block2 = BlockFactory.create_block_with_timestamp(
            [block1.get_hash()], BLOCK_TIME * 2 + 1)
        other_signed_block2 = BlockFactory.sign_block(other_block2, private)
        dag.add_signed_block(2, other_signed_block2)

        # alternative chain
        other_block3 = BlockFactory.create_block_with_timestamp(
            [other_block2.get_hash()], BLOCK_TIME * 3 + 1)
        other_signed_block3 = BlockFactory.sign_block(other_block3, private)
        dag.add_signed_block(3, other_signed_block3)

        self.assertEqual(
            dag.is_ancestor(other_block3.get_hash(), other_block2.get_hash()),
            True)
        self.assertEqual(
            dag.is_ancestor(other_block3.get_hash(), block2.get_hash()), False)
Beispiel #4
0
    def test_genesis_is_first_era_hash(self):
        dag = Dag(0)

        first_era_hash = dag.get_era_hash(1)
        genesis_hash = dag.genesis_block().get_hash().digest()

        self.assertEqual(first_era_hash, genesis_hash)
Beispiel #5
0
    def test_complex_merge(self):
        dag = Dag(0)
        genesis_hash = dag.genesis_block().get_hash()
        ChainGenerator.fill_with_dummies_and_skips(dag, genesis_hash,
                                                   range(1, 10), [2, 5, 7, 8])
        first_block = dag.blocks_by_number[1][0].get_hash()
        ChainGenerator.fill_with_dummies_and_skips(dag, first_block,
                                                   range(2, 10),
                                                   [3, 4, 6, 7, 8, 9])
        second_block = dag.blocks_by_number[2][0].get_hash()
        ChainGenerator.fill_with_dummies_and_skips(dag, second_block,
                                                   range(3, 10),
                                                   [3, 4, 5, 6, 9])

        merger = Merger(dag)
        res = merger.merge(dag.get_top_hashes())
        res = res.filter_out_skipped_blocks()
        # res.debug_print_block_numbers(dag)

        self.assertEqual(res[0], dag.blocks_by_number[1][0])
        self.assertEqual(res[1], dag.blocks_by_number[3][0])
        self.assertEqual(res[2], dag.blocks_by_number[4][0])
        self.assertEqual(res[3], dag.blocks_by_number[6][0])
        self.assertEqual(res[4], dag.blocks_by_number[9][0])
        self.assertEqual(
            res[5],
            dag.blocks_by_number[2][0])  # TODO find out why is this 2 here
        self.assertEqual(res[6], dag.blocks_by_number[7][0])
        self.assertEqual(res[7], dag.blocks_by_number[8][0])
        self.assertEqual(res[8], dag.blocks_by_number[5][0])
Beispiel #6
0
    def test_merge_with_conflict_simple(self):
        dag = Dag(0)

        genesis_hash = dag.genesis_block().get_hash()

        block_hash1 = ChainGenerator.insert_dummy(dag, [genesis_hash], 1)

        conflicting_block_hash1 = ChainGenerator.insert_dummy(
            dag, [block_hash1], 2)
        conflicting_block_hash2 = ChainGenerator.insert_dummy(
            dag, [block_hash1], 2)

        block_hash3 = ChainGenerator.insert_dummy(dag,
                                                  [conflicting_block_hash2], 3)

        # DagVisualizer.visualize(dag, True)  # uncomment for discover in visualization folder

        conflicts = [conflicting_block_hash1]

        merger = Merger(dag)
        res = merger.merge(dag.get_top_hashes(), conflicts)
        res = res.filter_out_skipped_blocks()

        # self.assertEqual(res[0].get_hash(), genesis_hash) #no genesis hash since common ancestor is first block
        self.assertEqual(res[0].get_hash(), block_hash1)
        self.assertEqual(res[1].get_hash(), conflicting_block_hash2)
        self.assertEqual(res[2].get_hash(), block_hash3)
Beispiel #7
0
    def test_top_blocks_in_range(self):
        dag = Dag(0)

        prev_hash = dag.genesis_block().get_hash()
        ChainGenerator.fill_with_dummies_and_skips(dag, prev_hash, range(1, 8),
                                                   [3, 5])
        ChainGenerator.fill_with_dummies_and_skips(dag, prev_hash, range(1, 8),
                                                   [4])
        ChainGenerator.fill_with_dummies_and_skips(dag, prev_hash, range(1, 7),
                                                   [4, 5])

        tops = dag.get_branches_for_timeslot_range(3, 6)

        self.assertEqual(len(tops), 3)
        self.assertIn(dag.blocks_by_number[4][0].get_hash(), tops)
        self.assertIn(dag.blocks_by_number[5][0].get_hash(), tops)
        self.assertIn(dag.blocks_by_number[3][1].get_hash(), tops)

        tops = dag.get_branches_for_timeslot_range(4, 5)

        self.assertEqual(len(tops), 1)
        self.assertIn(dag.blocks_by_number[4][0].get_hash(), tops)

        tops = dag.get_branches_for_timeslot_range(3, 5)
        self.assertEqual(len(tops), 3)
        self.assertIn(dag.blocks_by_number[4][0].get_hash(), tops)
        self.assertIn(dag.blocks_by_number[3][0].get_hash(), tops)
        self.assertIn(dag.blocks_by_number[3][1].get_hash(), tops)
    def test_conflicts_with_skips(self):
        dag = Dag(0)
        # generate test case
        # time_slot [0, 1, 2, 3, 4, 5]
        # -------------------------------
        # 1 ------- [0, 1, 2, 3,  , 5, 6, 7, 8]
        # 2 ------- [ ,  ,  , 3, 4,  , 6, 7, 8]
        # 3 ------- [ ,  ,  ,  , 4, 5, 6,  , 8]
        # block number 3 MUST BE signed by same key
        private1 = Private.generate()
        private2 = Private.generate()
        private3 = Private.generate()

        top_hash_1 = \
            ChainGenerator.fill_with_dummies_and_skips(dag=dag,
                                                           prev_hash=dag.genesis_block().get_hash(),
                                                           range=range(1, 9),
                                                           indices_to_skip=[4],
                                                           dummy_private=private1)
        top_hash_2 = \
            ChainGenerator.fill_with_dummies_and_skips(dag=dag,
                                                           prev_hash=dag.blocks_by_number[2][0].get_hash(),
                                                           range=range(3, 9),
                                                           indices_to_skip=[5],
                                                           dummy_private=private2)

        top_hash_3 = \
            ChainGenerator.fill_with_dummies_and_skips(dag=dag,
                                                           prev_hash=dag.blocks_by_number[3][1].get_hash(),
                                                           range=range(4, 9),
                                                           indices_to_skip=[7],
                                                           dummy_private=private3)

        # DagVisualizer.visualize(dag)

        conflict_finder = ConflictFinder(dag)
        top_blocks = list(dag.get_top_blocks().keys())
        top, conflicts = conflict_finder.find_conflicts(top_blocks)
        # assert determined top (it can be one of top_hash1,2,3)
        tops = [top_hash_1, top_hash_2, top_hash_3]
        self.assertIn(top, tops)
        if top == top_hash_1:
            # test conflicts
            # conflicts include all [3],[4,4],[5],[6,6],[7],[8,8]
            # EXCLUDE flatten top chain from list of conflict block hashes
            self.assertEqual(len(conflicts), 9)
        if top == top_hash_2:
            # test conflicts
            # conflicts include all [3],[4],[5,5],[6,6],[7],[8,8]
            # EXCLUDE flatten top chain from list of conflict block hashes
            self.assertEqual(len(conflicts), 9)
        if top == top_hash_3:
            # test conflicts
            # conflicts include all [3],[4],[5],[6,6],[7,7],[8,8]
            # EXCLUDE flatten top chain from list of conflict block hashes
            self.assertEqual(len(conflicts), 9)
    def test_complicated_dag_with_skips(self):
        dag = Dag(0)
        # generate test case
        # time_slot [0, 1, 2, 3, 4, 5]
        # -------------------------------
        # 1 ------- [-, -, 2, 3, 4, 5,  ,  , 8]
        # 2 ------- [0, 1, 2,  ,  , 5, 6, 7, 8]
        # 3 ------- [-, -, -, 3, 4,  , 6, 7, 8]
        # 4 ------- [-, -, -, -, 4, 5, 6,  , 8]
        # block number 3 MUST BE signed by same key
        private1 = Private.generate()
        private2 = Private.generate()
        private3 = Private.generate()
        private4 = Private.generate()

        top_hash_2 = \
            ChainGenerator.fill_with_dummies_and_skips(dag=dag,
                                                           prev_hash=dag.genesis_block().get_hash(),
                                                           range=range(1, 9),
                                                           indices_to_skip=[3, 4],
                                                           dummy_private=private2)

        top_hash_1 = \
            ChainGenerator.fill_with_dummies_and_skips(dag=dag,
                                                           prev_hash=dag.blocks_by_number[1][0].get_hash(),
                                                           range=range(2, 9),
                                                           indices_to_skip=[6, 7],
                                                           dummy_private=private1)

        top_hash_3 = \
            ChainGenerator.fill_with_dummies_and_skips(dag=dag,
                                                           prev_hash=dag.blocks_by_number[2][0].get_hash(),
                                                           range=range(3, 9),
                                                           indices_to_skip=[5],
                                                           dummy_private=private3)

        top_hash_4 = \
            ChainGenerator.fill_with_dummies_and_skips(dag=dag,
                                                           prev_hash=dag.blocks_by_number[3][1].get_hash(),
                                                           range=range(4, 9),
                                                           indices_to_skip=[7],
                                                           dummy_private=private4)

        # DagVisualizer.visualize(dag)

        conflict_finder = ConflictFinder(dag)
        top_blocks = list(dag.get_top_blocks().keys())
        top, conflicts = conflict_finder.find_conflicts(top_blocks)
        # assert determined top (it can be one of longest top_hash_3,4)
        tops = [top_hash_3, top_hash_4]
        self.assertIn(top, tops)
        # test conflicts
        self.assertEqual(len(conflicts), 13)
    def test_find_epoch_hash_for_block(self):
        dag = Dag(0)
        epoch = Epoch(dag)
        genesis_hash = dag.genesis_block().get_hash()
        genesis_epoch_hash = epoch.find_epoch_hash_for_block(genesis_hash)
        self.assertEqual(genesis_hash, genesis_epoch_hash)

        block = BlockFactory.create_block_with_timestamp([genesis_hash],
                                                         BLOCK_TIME)
        signed_block = BlockFactory.sign_block(block, Private.generate())
        dag.add_signed_block(1, signed_block)
        first_block_hash = block.get_hash()

        first_epoch_hash = epoch.find_epoch_hash_for_block(first_block_hash)
        self.assertEqual(genesis_hash, first_epoch_hash)
    def test_merge_in_merge(self):
        dag = Dag(0)
        genesis_hash = dag.genesis_block().get_hash()
        ChainGenerator.fill_with_dummies_and_skips(dag, genesis_hash,
                                                   range(1, 5), [1, 3])
        second_block = dag.blocks_by_number[2][0].get_hash()
        ChainGenerator.fill_with_dummies_and_skips(dag, second_block,
                                                   range(3, 4), [])
        tops = dag.get_top_hashes()
        merging_block = BlockFactory.create_block_with_timestamp(
            tops, BLOCK_TIME * 5)
        merging_signed_block = BlockFactory.sign_block(merging_block,
                                                       Private.generate())
        dag.add_signed_block(5, merging_signed_block)

        ChainGenerator.fill_with_dummies_and_skips(dag, genesis_hash,
                                                   range(1, 7), [2, 3, 4, 5])

        tops = dag.get_top_hashes()
        merging_block = BlockFactory.create_block_with_timestamp(
            tops, BLOCK_TIME * 7)
        merging_signed_block = BlockFactory.sign_block(merging_block,
                                                       Private.generate())
        dag.add_signed_block(7, merging_signed_block)

        # DagVisualizer.visualize(dag, True)

        iterator = MergingIter(dag, merging_block.get_hash())

        #shortest chain goes last
        # 3 and 4 are swapped because 4 has a priority
        #TODO But is it okay? Maybe we should sometimes give priority to earlier blocks if equal?1
        self.assertEqual(iterator.next().get_hash(),
                         dag.blocks_by_number[7][0].get_hash())
        self.assertEqual(iterator.next().get_hash(),
                         dag.blocks_by_number[6][0].get_hash())
        self.assertEqual(iterator.next().get_hash(),
                         dag.blocks_by_number[1][0].get_hash())
        self.assertEqual(iterator.next().get_hash(),
                         dag.blocks_by_number[5][0].get_hash())
        self.assertEqual(iterator.next().get_hash(),
                         dag.blocks_by_number[3][0].get_hash())
        self.assertEqual(iterator.next().get_hash(),
                         dag.blocks_by_number[4][0].get_hash())
        self.assertEqual(iterator.next().get_hash(),
                         dag.blocks_by_number[2][0].get_hash())
        self.assertEqual(iterator.next().get_hash(),
                         dag.blocks_by_number[0][0].get_hash())
    def test_sane_prev_hashes_found(self):
        dag = Dag(0)
        epoch = Epoch(dag)
        genesis_hash = dag.genesis_block().get_hash()

        block_hash1 = ChainGenerator.insert_dummy(dag, [genesis_hash], 1)
        block_hash2 = ChainGenerator.insert_dummy(dag, [block_hash1], 2)
        _block_hash3 = ChainGenerator.insert_dummy(dag,
                                                   [genesis_hash, block_hash2],
                                                   3)

        verifier = BlockAcceptor(epoch, None)

        with self.assertRaises(AcceptionException):
            verifier.validate_non_ancestor_prev_hashes(
                [genesis_hash, block_hash2])
Beispiel #13
0
    def test_merge(self):
        dag = Dag(0)
        prev_hash = dag.genesis_block().get_hash()
        ChainGenerator.fill_with_dummies_and_skips(dag, prev_hash, range(1, 4),
                                                   [1, 2])
        ChainGenerator.fill_with_dummies_and_skips(dag, prev_hash, range(1, 4),
                                                   [3])

        merger = Merger(dag)
        res = merger.merge(dag.get_top_hashes())
        res = res.filter_out_skipped_blocks()

        self.assertEqual(res[0], dag.blocks_by_number[0][0])
        self.assertEqual(res[1], dag.blocks_by_number[1][0])
        self.assertEqual(res[2], dag.blocks_by_number[2][0])
        self.assertEqual(res[3], dag.blocks_by_number[3][0])
Beispiel #14
0
    def test_skip_confirmation_requirement(self):
        dag = Dag(0)
        conf_req = ConfirmationRequirement(dag)

        genesis_hash = dag.genesis_block().get_hash()

        block_hash = ChainGenerator.insert_dummy(dag, [genesis_hash], 1)
        # confirmation requirement decreases because we have large skip
        confirmation_requirement = conf_req.get_confirmation_requirement(
            block_hash)
        self.assertEqual(confirmation_requirement, 5)

        block_hash = ChainGenerator.insert_dummy(dag, [block_hash], 3)
        skip = SkippedBlock(block_hash, 1)
        confirmation_requirement = conf_req.get_confirmation_requirement(skip)
        self.assertEqual(confirmation_requirement, 5)

        # do a larger gap
        block_hash = ChainGenerator.insert_dummy(dag, [block_hash], 11)

        confirmation_requirement = conf_req.get_confirmation_requirement(
            block_hash)
        self.assertEqual(confirmation_requirement, 3)

        confirmation_requirement = conf_req.get_confirmation_requirement(
            SkippedBlock(block_hash, 1))
        self.assertEqual(confirmation_requirement, 3)

        confirmation_requirement = conf_req.get_confirmation_requirement(
            SkippedBlock(block_hash, 2))
        self.assertEqual(confirmation_requirement, 4)

        confirmation_requirement = conf_req.get_confirmation_requirement(
            SkippedBlock(block_hash, 4))
        self.assertEqual(confirmation_requirement, 4)

        confirmation_requirement = conf_req.get_confirmation_requirement(
            SkippedBlock(block_hash, 5))
        self.assertEqual(confirmation_requirement, 5)

        confirmation_requirement = conf_req.get_confirmation_requirement(
            SkippedBlock(block_hash, 6))
        self.assertEqual(confirmation_requirement, 5)

        confirmation_requirement = conf_req.get_confirmation_requirement(
            SkippedBlock(block_hash, 10))
        self.assertEqual(confirmation_requirement, ZETA_MAX)
    def test_simple_merge(self):
        dag = Dag(0)
        genesis_hash = dag.genesis_block().get_hash()
        ChainGenerator.fill_with_dummies_and_skips(dag, genesis_hash,
                                                   range(1, 10), [2, 5, 7, 8])
        first_block = dag.blocks_by_number[1][0].get_hash()
        ChainGenerator.fill_with_dummies_and_skips(dag, first_block,
                                                   range(2, 10),
                                                   [3, 4, 6, 7, 8, 9])
        second_block = dag.blocks_by_number[2][0].get_hash()
        ChainGenerator.fill_with_dummies_and_skips(dag, second_block,
                                                   range(3, 10),
                                                   [3, 4, 5, 6, 9])

        hanging_tips = dag.get_top_hashes()

        merging_block = BlockFactory.create_block_with_timestamp(
            hanging_tips, BLOCK_TIME * 10)
        merging_signed_block = BlockFactory.sign_block(merging_block,
                                                       Private.generate())
        dag.add_signed_block(10, merging_signed_block)
        # DagVisualizer.visualize(dag, True)

        iterator = MergingIter(dag, merging_block.get_hash())

        self.assertEqual(iterator.next().get_hash(), merging_block.get_hash())
        self.assertEqual(iterator.next().get_hash(),
                         dag.blocks_by_number[5][0].get_hash())
        self.assertEqual(iterator.next().get_hash(),
                         dag.blocks_by_number[8][0].get_hash())
        self.assertEqual(iterator.next().get_hash(),
                         dag.blocks_by_number[7][0].get_hash())
        self.assertEqual(iterator.next().get_hash(), dag.blocks_by_number[2]
                         [0].get_hash())  #TODO find out why is this 2 here
        self.assertEqual(iterator.next().get_hash(),
                         dag.blocks_by_number[9][0].get_hash())
        self.assertEqual(iterator.next().get_hash(),
                         dag.blocks_by_number[6][0].get_hash())
        self.assertEqual(iterator.next().get_hash(),
                         dag.blocks_by_number[4][0].get_hash())
        self.assertEqual(iterator.next().get_hash(),
                         dag.blocks_by_number[3][0].get_hash())
        self.assertEqual(iterator.next().get_hash(),
                         dag.blocks_by_number[1][0].get_hash())
        self.assertEqual(iterator.next().get_hash(),
                         dag.blocks_by_number[0][0].get_hash())
Beispiel #16
0
    def test_iterator(self):
        dag = Dag(0)
        private = Private.generate()
        block1 = BlockFactory.create_block_with_timestamp(
            [dag.genesis_block().get_hash()], BLOCK_TIME)
        signed_block1 = BlockFactory.sign_block(block1, private)
        dag.add_signed_block(1, signed_block1)

        block2 = BlockFactory.create_block_with_timestamp([block1.get_hash()],
                                                          BLOCK_TIME * 2)
        signed_block2 = BlockFactory.sign_block(block2, private)
        dag.add_signed_block(2, signed_block2)

        block3 = BlockFactory.create_block_with_timestamp([block2.get_hash()],
                                                          BLOCK_TIME * 3)
        signed_block3 = BlockFactory.sign_block(block3, private)
        dag.add_signed_block(3, signed_block3)

        # alternative chain
        other_block2 = BlockFactory.create_block_with_timestamp(
            [block1.get_hash()], BLOCK_TIME * 2 + 1)
        other_signed_block2 = BlockFactory.sign_block(other_block2, private)
        dag.add_signed_block(2, other_signed_block2)

        # intentionally skipped block

        # alternative chain
        other_block4 = BlockFactory.create_block_with_timestamp(
            [other_block2.get_hash()], BLOCK_TIME * 3 + 1)
        other_signed_block4 = BlockFactory.sign_block(other_block4, private)
        dag.add_signed_block(4, other_signed_block4)

        chain_iter = ChainIter(dag, block3.get_hash())
        self.assertEqual(chain_iter.next().block.get_hash(), block3.get_hash())
        self.assertEqual(chain_iter.next().block.get_hash(), block2.get_hash())
        self.assertEqual(chain_iter.next().block.get_hash(), block1.get_hash())

        chain_iter = ChainIter(dag, other_block4.get_hash())
        self.assertEqual(chain_iter.next().block.get_hash(),
                         other_block4.get_hash())
        self.assertEqual(chain_iter.next(),
                         None)  # detect intentionally skipped block
        self.assertEqual(chain_iter.next().block.get_hash(),
                         other_block2.get_hash())
        self.assertEqual(chain_iter.next().block.get_hash(), block1.get_hash())
Beispiel #17
0
    def test_storing_tx_by_hash(self):
        dag = Dag(0)
        private0 = Private.generate()
        private1 = Private.generate()
        private2 = Private.generate()

        # add block 1
        block1 = BlockFactory.create_block_with_timestamp(
            [dag.genesis_block().get_hash()], BLOCK_TIME)
        signed_block1 = BlockFactory.sign_block(block1, private0)
        dag.add_signed_block(1, signed_block1)

        # check transactions in dag.transactions_by_hash for empty
        self.assertTrue(len(dag.transactions_by_hash) == 0)

        # add block 2
        block2 = BlockFactory.create_block_with_timestamp([block1.get_hash()],
                                                          BLOCK_TIME)
        # add penalty gossip case by tx in block
        tx1 = TransactionFactory.create_negative_gossip_transaction(
            1, private1)
        tx2 = TransactionFactory.create_positive_gossip_transaction(
            block2.get_hash(), private1)
        block2.system_txs.append(tx1)
        block2.system_txs.append(tx2)
        # --------------------------------------
        signed_block2 = BlockFactory.sign_block(block2, private1)
        dag.add_signed_block(2, signed_block2)

        # check transactions in dag.transactions_by_hash
        self.assertTrue(
            set(dag.transactions_by_hash).issuperset({tx1.get_hash(): tx1}))
        self.assertTrue(
            set(dag.transactions_by_hash).issuperset({tx2.get_hash(): tx2}))

        block3 = BlockFactory.create_block_with_timestamp([block2.get_hash()],
                                                          BLOCK_TIME)
        signed_block3 = BlockFactory.sign_block(block3, private2)
        dag.add_signed_block(3, signed_block3)

        # check transactions in dag.transactions_by_hash
        self.assertTrue(
            set(dag.transactions_by_hash).issuperset({tx1.get_hash(): tx1}))
        self.assertTrue(
            set(dag.transactions_by_hash).issuperset({tx2.get_hash(): tx2}))
Beispiel #18
0
    def test_merge_with_conflict_simplest(self):
        dag = Dag(0)

        genesis_hash = dag.genesis_block().get_hash()

        block_hash1 = ChainGenerator.insert_dummy(dag, [genesis_hash], 1)
        block_hash2 = ChainGenerator.insert_dummy(dag, [genesis_hash], 1)

        # DagVisualizer.visualize(dag, True)  # uncomment for discover in visualization folder

        conflicts = [block_hash1]

        merger = Merger(dag)
        res = merger.merge(dag.get_top_hashes(), conflicts)
        res = res.filter_out_skipped_blocks()

        self.assertEqual(res[0].get_hash(), genesis_hash)
        self.assertEqual(res[1].get_hash(), block_hash2)
Beispiel #19
0
    def test_zeta_calculation(self):
        dag = Dag(0)
        private = Private.generate()
        prev_hash = dag.genesis_block().get_hash()
        for i in range(1, 3):
            block = BlockFactory.create_block_with_timestamp([prev_hash],
                                                             BLOCK_TIME * i)
            signed_block = BlockFactory.sign_block(block, private)
            dag.add_signed_block(i, signed_block)
            prev_hash = block.get_hash()

        #skip 3 blocks

        for i in range(6, 7):
            block = BlockFactory.create_block_with_timestamp([prev_hash],
                                                             BLOCK_TIME * i)
            signed_block = BlockFactory.sign_block(block, private)
            dag.add_signed_block(i, signed_block)
            prev_hash = block.get_hash()

        for i in range(10, 12):
            block = BlockFactory.create_block_with_timestamp([prev_hash],
                                                             BLOCK_TIME * i)
            signed_block = BlockFactory.sign_block(block, private)
            dag.add_signed_block(i, signed_block)
            prev_hash = block.get_hash()

        prev_hash = dag.blocks_by_number[1][0].get_hash()
        for i in range(2, 12):
            if i == 3: continue
            block = BlockFactory.create_block_with_timestamp(
                [prev_hash], BLOCK_TIME * i + 1)
            signed_block = BlockFactory.sign_block(block, private)
            dag.add_signed_block(i, signed_block)
            prev_hash = block.get_hash()

        immutability = Immutability(dag)
        # zeta = immutability.calculate_zeta(dag.blocks_by_number[2][0].get_hash())
        # self.assertEqual(zeta, -2)

        zeta = immutability.calculate_zeta(
            dag.blocks_by_number[6][1].get_hash())
        self.assertEqual(zeta, 1)
    def test_sane_prev_hashes_not_found(self):
        dag = Dag(0)
        epoch = Epoch(dag)
        genesis_hash = dag.genesis_block().get_hash()

        block_hash1 = ChainGenerator.insert_dummy(dag, [genesis_hash], 1)
        block_hash2 = ChainGenerator.insert_dummy(dag, [block_hash1], 2)
        block_hash3 = ChainGenerator.insert_dummy(dag, [genesis_hash], 3)
        _block_hash4 = ChainGenerator.insert_dummy(dag,
                                                   [block_hash2, block_hash3],
                                                   4)

        verifier = BlockAcceptor(epoch, None)

        try:
            verifier.validate_non_ancestor_prev_hashes(
                [block_hash2, block_hash3])
        except:
            self.fail("Prev hashes should not be self referential")
    def test_penalty(self):
        dag = Dag(0)
        epoch = Epoch(dag)
        permissions = Permissions(epoch)
        node_private = Private.generate()

        initial_validators = Validators.read_genesis_validators_from_file()

        genesis_hash = dag.genesis_block().get_hash()

        last_block_number = Epoch.get_epoch_end_block_number(1)
        prev_hash = ChainGenerator.fill_with_dummies(
            dag, genesis_hash, range(1, last_block_number))

        block = BlockFactory.create_block_with_timestamp(
            [prev_hash], BLOCK_TIME * last_block_number)
        tx = PenaltyTransaction()
        tx.conflicts = [prev_hash]
        tx.signature = Private.sign(tx.get_hash(), node_private)
        block.system_txs = [tx]
        signed_block = BlockFactory.sign_block(block, node_private)
        dag.add_signed_block(last_block_number, signed_block)

        initial_validators_order = permissions.get_signers_indexes(
            genesis_hash)
        # we substract two here: one because it is last but one block
        # and one, because epoch starts from 1
        validator_index_to_penalize = initial_validators_order[
            last_block_number - 2]

        resulting_validators = permissions.get_validators(block.get_hash())

        self.assertNotEqual(len(initial_validators), len(resulting_validators))

        initial_validators.pop(validator_index_to_penalize)

        init_pubkeys = list(
            map(lambda validator: validator.public_key, initial_validators))
        result_pubkeys = list(
            map(lambda validator: validator.public_key, resulting_validators))

        self.assertEqual(init_pubkeys, result_pubkeys)
Beispiel #22
0
    def test_multiple_chain_common_ancestor(self):
        dag = Dag(0)
        genesis_hash = dag.genesis_block().get_hash()
        ChainGenerator.fill_with_dummies_and_skips(dag, genesis_hash,
                                                   range(1, 10), [2, 5, 7, 8])
        first_block = dag.blocks_by_number[1][0].get_hash()
        ChainGenerator.fill_with_dummies_and_skips(dag, first_block,
                                                   range(2, 10),
                                                   [3, 4, 6, 7, 8, 9])
        second_block = dag.blocks_by_number[2][0].get_hash()
        ChainGenerator.fill_with_dummies_and_skips(dag, second_block,
                                                   range(3, 10),
                                                   [3, 4, 5, 6, 9])
        expected_intersection = dag.blocks_by_number[1][0].get_hash()

        tops = dag.get_top_blocks_hashes()
        found_intersection = dag.get_common_ancestor(
            [tops[0], tops[1], tops[2]])

        self.assertEqual(expected_intersection, found_intersection)
Beispiel #23
0
    def test_skips_and_restoring(self):
        dag = Dag(0)
        conf_req = ConfirmationRequirement(dag)

        genesis_hash = dag.genesis_block().get_hash()

        block_hash = ChainGenerator.insert_dummy(dag, [genesis_hash], 1)
        conf_req.blocks[block_hash] = 5
        block_hash = ChainGenerator.insert_dummy(dag, [block_hash], 5)

        # confirmation requirement decreases because we have large skip
        confirmation_requirement = conf_req.get_confirmation_requirement(
            block_hash)
        self.assertEqual(confirmation_requirement, 4)

        block_hash = ChainGenerator.insert_dummy(dag, [block_hash], 6)
        block_hash = ChainGenerator.insert_dummy(dag, [block_hash], 7)

        #we still have 4 here
        confirmation_requirement = conf_req.get_confirmation_requirement(
            block_hash)
        self.assertEqual(confirmation_requirement, 4)

        block_hash = ChainGenerator.insert_dummy(dag, [block_hash], 8)

        #but we have restored to 5 here, because of 3 previous consecutive blocks
        confirmation_requirement = conf_req.get_confirmation_requirement(
            block_hash)
        self.assertEqual(confirmation_requirement, 5)

        #let's skip one
        block_hash = ChainGenerator.insert_dummy(dag, [block_hash], 10)

        block_hash = ChainGenerator.insert_dummy(dag, [block_hash], 11)

        # DagVisualizer.visualize(dag, True) # take a look to understand what's going on

        #not affected by small skip
        confirmation_requirement = conf_req.get_confirmation_requirement(
            block_hash)
        self.assertEqual(confirmation_requirement, 5)
    def test_find_conflicts_longest_chain(self):
        dag = Dag(0)
        # generate test case
        # time_slot [0, 1, 2, 3, 4, 5, 6]
        # -------------------------------
        # 1 ------- [0, 1, 2, 3, 4, 5, 6]
        # 2 ------- [ ,  ,  , 3, 4, 5,  ]
        # 3 ------- [ ,  ,  ,  , 4, 5,  ]
        # block number 3 MUST BE signed by same key
        private1 = Private.generate()
        private2 = Private.generate()
        private3 = Private.generate()

        determinated_top_hash = \
        ChainGenerator.fill_with_dummies_and_skips(dag=dag,
                                                       prev_hash=dag.genesis_block().get_hash(),
                                                       range=range(1, 7),
                                                       indices_to_skip=[],
                                                       dummy_private=private1)

        ChainGenerator.fill_with_dummies_and_skips(dag=dag,
                                                       prev_hash=dag.blocks_by_number[2][0].get_hash(),
                                                       range=range(3, 6),
                                                       indices_to_skip=[],
                                                       dummy_private=private2)

        ChainGenerator.fill_with_dummies_and_skips(dag=dag,
                                                       prev_hash=dag.blocks_by_number[3][1].get_hash(),
                                                       range=range(4, 6),
                                                       indices_to_skip=[],
                                                       dummy_private=private3)

        # DagVisualizer.visualize(dag)

        conflict_finder = ConflictFinder(dag)
        top_blocks = list(dag.get_top_blocks().keys())
        top, conflicts = conflict_finder.find_conflicts(top_blocks)
        # assert determined top
        self.assertEqual(determinated_top_hash, top)
        # test conflicts [3],[4,4],[5,5] EXCLUDE flatten top chain from list of conflict block hashes
        self.assertEqual(len(conflicts), 5)
Beispiel #25
0
    def generate_two_chains(length):
        dag = Dag(0)
        private = Private.generate()
        prev_hash = dag.genesis_block().get_hash()
        for i in range(1, length + 1):
            block = BlockFactory.create_block_with_timestamp([prev_hash],
                                                             BLOCK_TIME * i)
            signed_block = BlockFactory.sign_block(block, private)
            dag.add_signed_block(i, signed_block)
            prev_hash = block.get_hash()

        prev_hash = dag.blocks_by_number[1][0].get_hash()
        for i in range(2, length + 1):  # intentionally one block less
            if i == 4: continue  # intentionally skipped block
            block = BlockFactory.create_block_with_timestamp(
                [prev_hash], BLOCK_TIME * i + 1)
            signed_block = BlockFactory.sign_block(block, private)
            dag.add_signed_block(i, signed_block)
            prev_hash = block.get_hash()

        return dag
Beispiel #26
0
    def test_recursive_sequence_found(self):
        dag = Dag(0)
        conf_req = ConfirmationRequirement(dag)

        genesis_hash = dag.genesis_block().get_hash()

        block_hash = ChainGenerator.insert_dummy(dag, [genesis_hash], 1)
        conf_req.blocks[block_hash] = 2
        block_hash = ChainGenerator.insert_dummy(dag, [genesis_hash], 1)
        conf_req.blocks[block_hash] = 3

        block_hash = ChainGenerator.insert_dummy(dag, dag.get_top_hashes(), 2)
        conf_req.blocks[block_hash] = 3

        last_block_in_seq_hash = ChainGenerator.insert_dummy(
            dag, [genesis_hash], 1)
        conf_req.blocks[last_block_in_seq_hash] = 3
        block_hash = ChainGenerator.insert_dummy(dag, [genesis_hash], 1)
        conf_req.blocks[block_hash] = 3

        block_hash = ChainGenerator.insert_dummy(
            dag, [last_block_in_seq_hash, block_hash], 2)
        conf_req.blocks[block_hash] = 4

        block_hash = ChainGenerator.insert_dummy(dag, dag.get_top_hashes(), 3)
        conf_req.blocks[block_hash] = 4

        block_hash = ChainGenerator.insert_dummy(dag, dag.get_top_hashes(), 4)

        # DagVisualizer.visualize(dag, True) # take a look to understand what's going on

        # there will be only two blocks with consecutive 4 behind, which is not enough to increase
        best_requirement = conf_req.choose_next_best_requirement(block_hash)
        self.assertEqual(best_requirement, 4)

        # make three blocks with consecutive 4 behind
        # it should lead to following block increasing requirement value
        conf_req.blocks[last_block_in_seq_hash] = 4
        best_requirement = conf_req.choose_next_best_requirement(block_hash)
        self.assertEqual(best_requirement, 5)
    def test_stake_release_by_genesis_validator(self):
        # base initialization
        dag = Dag(0)
        epoch = Epoch(dag)
        permissions = Permissions(epoch)
        node_private = Private.generate()

        initial_validators = Validators.read_genesis_validators_from_file()

        genesis_hash = dag.genesis_block().get_hash()
        prev_hash = genesis_hash
        for i in range(1, 9):
            block = BlockFactory.create_block_with_timestamp([prev_hash],
                                                             BLOCK_TIME * i)
            signed_block = BlockFactory.sign_block(block, node_private)
            dag.add_signed_block(i, signed_block)
            prev_hash = block.get_hash()

        # get one of validators
        genesis_validator = initial_validators[9]

        # create stake release transaction for new stakeholder
        tx_release = StakeReleaseTransaction()
        tx_release.pubkey = Keys.to_bytes(genesis_validator.public_key)
        tx_release.signature = Private.sign(tx_release.get_hash(),
                                            node_private)

        # append signed stake release transaction
        block.system_txs.append(tx_release)

        # sign block by one of validators
        signed_block = BlockFactory.sign_block(block, node_private)
        # add signed block to DAG
        dag.add_signed_block(19, signed_block)

        resulting_validators = permissions.get_validators(block.get_hash())
        pub_keys = []
        for validator in resulting_validators:
            pub_keys.append(validator.public_key)
        self.assertNotIn(genesis_validator.public_key, pub_keys)
    def test_private_keys_extraction(self):
        dag = Dag(0)
        epoch = Epoch(dag)
        node_private = Private.generate()

        prev_hash = dag.genesis_block().get_hash()
        round_start, round_end = Epoch.get_round_bounds(1, Round.PRIVATE)
        for i in range(1, round_start):
            block = BlockFactory.create_block_with_timestamp([prev_hash],
                                                             BLOCK_TIME * i)
            signed_block = BlockFactory.sign_block(block, node_private)
            dag.add_signed_block(i, signed_block)
            prev_hash = block.get_hash()

        generated_private_keys = []
        for i in range(round_start,
                       round_end):  # intentionally skip last block of round
            generated_private = Private.generate()
            generated_private_keys.append(Keys.to_bytes(generated_private))

            private_key_tx = PrivateKeyTransaction()
            private_key_tx.key = Keys.to_bytes(generated_private)
            block = Block()
            block.system_txs = [private_key_tx]
            block.prev_hashes = dag.get_top_blocks_hashes()
            block.timestamp = i * BLOCK_TIME
            signed_block = BlockFactory.sign_block(block, node_private)
            dag.add_signed_block(i, signed_block)
            prev_hash = block.get_hash()

        ChainGenerator.fill_with_dummies(dag, prev_hash,
                                         Epoch.get_round_range(1, Round.FINAL))

        epoch_hash = dag.blocks_by_number[ROUND_DURATION * 6 + 1][0].get_hash()

        extracted_privates = epoch.get_private_keys_for_epoch(epoch_hash)

        for i in range(0, ROUND_DURATION - 1):
            self.assertEqual(extracted_privates[i], generated_private_keys[i])
Beispiel #29
0
    def test_top_blocks(self):
        dag = Dag(0)
        private = Private.generate()
        block1 = BlockFactory.create_block_with_timestamp(
            [dag.genesis_block().get_hash()], BLOCK_TIME)
        signed_block1 = BlockFactory.sign_block(block1, private)
        dag.add_signed_block(1, signed_block1)

        block2 = BlockFactory.create_block_with_timestamp([block1.get_hash()],
                                                          BLOCK_TIME * 2)
        signed_block2 = BlockFactory.sign_block(block2, private)
        dag.add_signed_block(2, signed_block2)

        block3 = BlockFactory.create_block_with_timestamp([block1.get_hash()],
                                                          BLOCK_TIME * 3)
        signed_block3 = BlockFactory.sign_block(block3, private)
        dag.add_signed_block(3, signed_block3)

        top_hashes = dag.get_top_blocks_hashes()

        self.assertEqual(top_hashes[0], block2.get_hash())
        self.assertEqual(top_hashes[1], block3.get_hash())
Beispiel #30
0
    def test_recursive_sequence_skips(self):
        dag = Dag(0)
        conf_req = ConfirmationRequirement(dag)

        genesis_hash = dag.genesis_block().get_hash()

        block_hash = ChainGenerator.insert_dummy(dag, [genesis_hash], 1)
        conf_req.blocks[block_hash] = 5
        block_hash = ChainGenerator.insert_dummy(dag, [block_hash], 5)

        # confirmation requirement decreases because we have large skip
        confirmation_requirement = conf_req.get_confirmation_requirement(
            block_hash)
        self.assertEqual(confirmation_requirement, 4)

        block_hash = ChainGenerator.insert_dummy(dag, [block_hash], 9)

        # DagVisualizer.visualize(dag, True) # take a look to understand what's going on

        confirmation_requirement = conf_req.get_confirmation_requirement(
            block_hash)
        self.assertEqual(confirmation_requirement, 3)