Beispiel #1
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)
    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)
Beispiel #3
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)
Beispiel #4
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])
Beispiel #5
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)
Beispiel #6
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)
Beispiel #7
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])
Beispiel #8
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_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_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)
Beispiel #11
0
    def test_explicit_conflict_right_on_common_ancestor(self):
        dag = Dag(0)
        watcher = ConflictWatcher(dag)

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

        #consider common ancestor already resolved
        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, actor2)

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

        tops = dag.get_top_hashes()

        explicits, candidates = watcher.find_conflicts_in_between(tops)
        self.assertEqual(len(explicits), 2)
        self.assertEqual(len(candidates), 0)
        self.assertIn(block2_hash, explicits)
        self.assertIn(block2c_hash, explicits)
    def test_merged_chain_with_block_conflict(self):
        dag = Dag(0)
        watcher = ConflictWatcher(dag)

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

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

        payment1 = TransactionFactory.create_payment(block1_reward, 0,
                                                     [os.urandom(32)], [15])
        block2_hash, block2_reward = ChainGenerator.insert_dummy_with_payments(
            dag, [block1_hash], [payment1], 2)
        watcher.on_new_block_by_validator(block2_hash, 1, actor2)

        #another block by the same validator spending the same output
        payment1c = TransactionFactory.create_payment(block1_reward, 0,
                                                      [os.urandom(32)], [15])
        block2c_hash, block2c_reward = ChainGenerator.insert_dummy_with_payments(
            dag, [block1_hash], [payment1c], 2)
        watcher.on_new_block_by_validator(block2c_hash, 1, actor2)

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

        # DagVisualizer.visualize(dag, True)

        iterator = MergingIter(dag, block3_hash, watcher)

        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), 3)

        self.assertIn(Entry(block2_reward, 0), unspent)
        self.assertIn(Entry(block3_reward, 0), unspent)
        self.assertIn(Entry(payment1.get_hash(), 0), unspent)
        self.assertNotIn(Entry(payment1c.get_hash(), 0), unspent)

        total_block_rewards = 0
        iterator = MergingIter(dag, block3_hash, watcher)
        for block in iterator:
            if block:
                if not block.block.payment_txs:
                    continue  #it might be genesis, or just some silly validator who decided not to earn a reward
                block_reward = block.block.payment_txs[0]
                total_block_rewards += block_reward.amounts[0]

        unspent_total = 0
        unspent_list = unspent  #HACKY rename :)
        for unspent in unspent_list:
            unspent_tx = dag.payments_by_hash[unspent.tx]
            unspent_output = unspent.number
            unspent_amount = unspent_tx.amounts[unspent_output]
            unspent_total += unspent_amount

        self.assertEqual(total_block_rewards, unspent_total)