Пример #1
0
    def test_same_timeslot_watch(self):
        dag = Dag(0)
        conflict_watcher = ConflictWatcher(dag)

        actor1 = Private.publickey(Private.generate())
        actor2 = Private.publickey(Private.generate())
        actor3 = Private.publickey(Private.generate())

        block1_hash = ChainGenerator.insert_dummy(dag, [dag.genesis_hash()], 1)
        conflict_watcher.on_new_block_by_validator(block1_hash, 1, actor1)

        block2_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2)
        conflict_watcher.on_new_block_by_validator(block2_hash, 1, actor2)

        block2c_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2)
        conflict_watcher.on_new_block_by_validator(block2c_hash, 1, actor2)

        block3_hash = ChainGenerator.insert_dummy(dag,
                                                  [block2_hash, block2c_hash],
                                                  3)
        conflict_watcher.on_new_block_by_validator(block3_hash, 1, actor3)

        conflicts = conflict_watcher.get_conflicts_by_block(block2_hash)
        self.assertEqual(len(conflicts), 2)
        self.assertIn(block2_hash, conflicts)
        self.assertIn(block2c_hash, conflicts)

        conflicts = conflict_watcher.get_conflicts_by_block(block1_hash)
        self.assertEqual(conflicts, None)
Пример #2
0
    def test_explicit_conflict(self):
        dag = Dag(0)
        watcher = ConflictWatcher(dag)

        actor1 = Private.publickey(Private.generate())
        actor2 = Private.publickey(Private.generate())

        block1_hash = ChainGenerator.insert_dummy(dag, [dag.genesis_hash()], 1)
        watcher.on_new_block_by_validator(block1_hash, 1, actor2)

        block2_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2)
        watcher.on_new_block_by_validator(block2_hash, 1, actor1)

        block3_hash = ChainGenerator.insert_dummy(dag, [block2_hash], 3)
        watcher.on_new_block_by_validator(block3_hash, 1, actor2)

        block3c_hash = ChainGenerator.insert_dummy(dag, [block2_hash], 3)
        watcher.on_new_block_by_validator(block3c_hash, 1, actor2)

        tops = dag.get_top_hashes()

        #here block was signed by node even before merge appeared
        #this is explicit merge and both following blocks are conflicting
        explicits, candidates = watcher.find_conflicts_in_between(tops)
        self.assertEqual(len(explicits), 2)
        self.assertEqual(len(candidates), 0)
        self.assertIn(block3_hash, explicits)
        self.assertIn(block3c_hash, explicits)
Пример #3
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)
Пример #4
0
    def test_different_timeslot_watch(self):
        dag = Dag(0)
        conflict_watcher = ConflictWatcher(dag)

        actor1 = Private.publickey(Private.generate())
        actor2 = Private.publickey(Private.generate())
        actor3 = Private.publickey(Private.generate())

        block1_hash = ChainGenerator.insert_dummy(dag, [dag.genesis_hash()], 1)
        conflict_watcher.on_new_block_by_validator(block1_hash, 1, actor1)

        block2_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2)
        conflict_watcher.on_new_block_by_validator(block2_hash, 1, actor2)

        # second block is signed by third validator
        # its not possible by usual means, but quite possible when we have two different epoch seeds
        block2c_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2)
        conflict_watcher.on_new_block_by_validator(block2c_hash, 1, actor3)

        block3_hash = ChainGenerator.insert_dummy(dag,
                                                  [block2_hash, block2c_hash],
                                                  3)
        conflict_watcher.on_new_block_by_validator(block3_hash, 1, actor3)

        conflicts = conflict_watcher.get_conflicts_by_block(block3_hash)
        self.assertEqual(len(conflicts), 2)
        self.assertIn(block2c_hash, conflicts)
        self.assertIn(block3_hash, conflicts)
    def test_merged_chain_without_transaction_conflicts(self):
        dag = Dag(0)

        block_hash, block_reward = ChainGenerator.insert_dummy_with_payments(
            dag, [dag.genesis_hash()], [], 1)

        payment1 = TransactionFactory.create_payment(block_reward, 0,
                                                     [os.urandom(32)], [15])
        block2_hash, block2_reward = ChainGenerator.insert_dummy_with_payments(
            dag, [block_hash], [payment1], 2)

        payment2 = TransactionFactory.create_payment(block2_reward, 0,
                                                     [os.urandom(32)], [15])
        block3_hash, block3_reward = ChainGenerator.insert_dummy_with_payments(
            dag, [block_hash], [payment2], 3)

        block4_hash, block4_reward = ChainGenerator.insert_dummy_with_payments(
            dag, [block2_hash, block3_hash], [], 4)

        iterator = MergingIter(dag, block4_hash)
        payments = [
            block.block.payment_txs for block in iterator if block != None
        ]
        payments = list(reversed(payments))

        spent, unspent = Resolver.resolve(payments)

        self.assertEqual(len(spent), 0)

        self.assertEqual(len(unspent), 4)

        self.assertIn(Entry(block3_reward, 0), unspent)
        self.assertIn(Entry(block4_reward, 0), unspent)
        self.assertIn(Entry(payment1.get_hash(), 0), unspent)
        self.assertIn(Entry(payment2.get_hash(), 0), unspent)
Пример #6
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])
Пример #7
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)
Пример #8
0
    def test_find_conflicts(self):
        dag = Dag(0)
        watcher = ConflictWatcher(dag)

        actor1 = Private.publickey(Private.generate())
        actor2 = Private.publickey(Private.generate())

        block1_hash = ChainGenerator.insert_dummy(dag, [dag.genesis_hash()], 1)
        watcher.on_new_block_by_validator(block1_hash, 1, actor1)

        block2_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2)
        watcher.on_new_block_by_validator(block2_hash, 1, actor2)

        block2c_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2)
        watcher.on_new_block_by_validator(block2c_hash, 1, actor2)

        # block3_hash = ChainGenerator.insert_dummy(dag, [block2_hash, block2c_hash], 3)
        # watcher.on_new_block_by_validator(block3_hash, 1, actor3)

        tops = dag.get_top_hashes()

        explicits, candidate_groups = watcher.find_conflicts_in_between(tops)
        self.assertEqual(len(explicits), 0)
        self.assertEqual(len(candidate_groups), 1)
        self.assertEqual(len(candidate_groups[0]), 2)
        self.assertIn(block2_hash, candidate_groups[0])
        self.assertIn(block2c_hash, candidate_groups[0])
Пример #9
0
    def test_both_types_of_conflicts(self):
        dag = Dag(0)
        watcher = ConflictWatcher(dag)

        actor1 = Private.publickey(Private.generate())
        actor2 = Private.publickey(Private.generate())
        actor3 = Private.publickey(Private.generate())

        block1_hash = ChainGenerator.insert_dummy(dag, [dag.genesis_hash()], 1)
        watcher.on_new_block_by_validator(block1_hash, 1, actor1)

        block2_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2)
        watcher.on_new_block_by_validator(block2_hash, 1, actor2)

        block2c_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2)
        watcher.on_new_block_by_validator(block2c_hash, 1, actor2)

        block3_hash = ChainGenerator.insert_dummy(dag, [block2_hash], 3)
        watcher.on_new_block_by_validator(block3_hash, 1, actor3)

        #this is possible if we have two epoch seeds
        block4_hash = ChainGenerator.insert_dummy(dag, [block2c_hash], 4)
        watcher.on_new_block_by_validator(block4_hash, 1, actor1)

        tops = dag.get_top_hashes()

        explicits, candidate_groups = watcher.find_conflicts_in_between(tops)
        self.assertEqual(len(explicits), 1)
        self.assertIn(block4_hash, explicits)

        self.assertEqual(len(candidate_groups), 1)
        self.assertEqual(len(candidate_groups[0]), 2)
        self.assertIn(block2_hash, candidate_groups[0])
        self.assertIn(block2c_hash, candidate_groups[0])
Пример #10
0
    def __init__(self, genesis_creation_time, node_id, network, block_signer):
        self.dag = Dag(genesis_creation_time)
        self.permissions = Permissions()
        self.mempool = Mempool()

        self.block_signer = block_signer
        self.network = network
        self.node_id = node_id
    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)
Пример #14
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])
    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])
Пример #16
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)
Пример #17
0
 def __init__(self, genesis_creation_time, logger):
     self.logger = logger
     self.dag = Dag(genesis_creation_time)
     self.epoch = Epoch(self.dag)
     self.epoch.set_logger(self.logger)
     self.logger.info("Starting announcer node")
     self.last_announced_round = None
     self.terminated = False
Пример #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)
    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())
Пример #20
0
    def test_different_epoch_watch(self):
        dag = Dag(0)
        conflict_watcher = ConflictWatcher(dag)

        actor1 = Private.publickey(Private.generate())
        actor2 = Private.publickey(Private.generate())
        actor3 = Private.publickey(Private.generate())

        block1_hash = ChainGenerator.insert_dummy(dag, [dag.genesis_hash()], 1)
        conflict_watcher.on_new_block_by_validator(block1_hash, 1, actor1)

        block2_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2)
        conflict_watcher.on_new_block_by_validator(block2_hash, 1, actor2)

        block2c_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2)
        conflict_watcher.on_new_block_by_validator(block2c_hash, 1, actor2)

        block3_hash = ChainGenerator.insert_dummy(dag,
                                                  [block2_hash, block2c_hash],
                                                  3)
        conflict_watcher.on_new_block_by_validator(block3_hash, 1, actor3)

        #switch to next epoch
        block4_hash = ChainGenerator.insert_dummy(dag, [block3_hash], 4)
        conflict_watcher.on_new_block_by_validator(block4_hash, 2, actor2)

        block4c_hash = ChainGenerator.insert_dummy(dag, [block3_hash], 4)
        conflict_watcher.on_new_block_by_validator(block4c_hash, 2, actor2)

        #first epoch conflicts
        conflicts = conflict_watcher.get_conflicts_by_block(block2_hash)
        self.assertEqual(len(conflicts), 2)
        self.assertIn(block2_hash, conflicts)
        self.assertIn(block2c_hash, conflicts)

        #second epoch conflicts of the same public key
        conflicts = conflict_watcher.get_conflicts_by_block(block4_hash)
        self.assertEqual(len(conflicts), 2)
        self.assertIn(block4_hash, conflicts)
        self.assertIn(block4c_hash, conflicts)

        conflicts = conflict_watcher.get_conflicts_by_block(block1_hash)
        self.assertEqual(conflicts, None)
    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)
Пример #23
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)
    def test_merged_chain_with_transaction_conflicts(self):
        dag = Dag(0)

        block_hash, block_reward = ChainGenerator.insert_dummy_with_payments(
            dag, [dag.genesis_hash()], [], 1)

        #second block spends first block reward
        payment1 = TransactionFactory.create_payment(block_reward, 0,
                                                     [os.urandom(32)], [15])
        block2_hash, block2_reward = ChainGenerator.insert_dummy_with_payments(
            dag, [block_hash], [payment1], 2)

        #third block also spends first block reward
        payment2 = TransactionFactory.create_payment(block_reward, 0,
                                                     [os.urandom(32)], [15])
        block3_hash, block3_reward = ChainGenerator.insert_dummy_with_payments(
            dag, [block_hash], [payment2], 3)

        #making block2_hash go first, so its transactions will have a priority
        block4_hash, block4_reward = ChainGenerator.insert_dummy_with_payments(
            dag, [block2_hash, block3_hash], [], 4)

        iterator = MergingIter(dag, block4_hash)
        payments = [
            block.block.payment_txs for block in iterator if block != None
        ]
        payments = list(reversed(payments))

        spent, unspent = Resolver.resolve(payments)

        self.assertEqual(len(spent), 0)

        self.assertEqual(len(unspent), 4)

        self.assertIn(Entry(block2_reward, 0), unspent)
        self.assertIn(Entry(block3_reward, 0), unspent)
        self.assertIn(Entry(block4_reward, 0), unspent)
        self.assertIn(Entry(payment1.get_hash(), 0), unspent)
        self.assertNotIn(
            Entry(payment2.get_hash(), 0), unspent
        )  #payment 2 is consedered conflicting as it goes later in merged chain
    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)
Пример #26
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_simple(self):
        dag = Dag(0)

        block_hash, block_reward = ChainGenerator.insert_dummy_with_payments(
            dag, [dag.genesis_hash()], [], 1)

        payment = TransactionFactory.create_payment(block_reward, 0,
                                                    [os.urandom(32)], [12])
        block2_hash, block2_reward = ChainGenerator.insert_dummy_with_payments(
            dag, [block_hash], [payment], 2)

        iterator = MergingIter(dag, block2_hash)
        payments = [block.block.payment_txs for block in iterator]
        payments = list(reversed(payments))

        spent, unspent = Resolver.resolve(payments)

        self.assertEqual(len(spent), 0)

        self.assertIn(Entry(block2_reward, 0), unspent)
        self.assertIn(Entry(payment.get_hash(), 0), unspent)
Пример #28
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}))
Пример #29
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)
Пример #30
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())