Example #1
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)
Example #2
0
 def insert_dummy(dag, prev_hashes, position):
     dummy_private = Private.generate()
     dummy_time_offset = len(dag.blocks_by_number.get(position, []))
     assert dummy_time_offset <= BLOCK_TIME, "This much blocks in one timeslot may lead to problems"
     block = BlockFactory.create_block_with_timestamp(
         prev_hashes, BLOCK_TIME * position + dummy_time_offset)
     signed_block = BlockFactory.sign_block(block, dummy_private)
     dag.add_signed_block(position, signed_block)
     return block.get_hash()
Example #3
0
 def insert_dummy_with_payments(dag, prev_hashes, payments, position):
     dummy_private = Private.generate()
     dummy_time_offset = len(dag.blocks_by_number.get(position, []))
     assert dummy_time_offset <= BLOCK_TIME, "This much blocks in one timeslot may lead to problems"
     block = BlockFactory.create_block_with_timestamp(
         prev_hashes, BLOCK_TIME * position + dummy_time_offset)
     block_reward = TransactionFactory.create_block_reward(
         urandom(32), position)
     block.payment_txs = [block_reward] + payments
     signed_block = BlockFactory.sign_block(block, dummy_private)
     dag.add_signed_block(position, signed_block)
     return block.get_hash(), block_reward.get_hash()
Example #4
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_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_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())
    def test_parse_pack_gossip_positive(self):
        private = Private.generate()
        original = PositiveGossipTransaction()
        original.pubkey = Private.publickey(private)
        original.timestamp = Time.get_current_time()

        block = BlockFactory.create_block_with_timestamp(
            [], timestamp=original.timestamp)
        original.block_hash = BlockFactory.sign_block(block,
                                                      private).get_hash()
        original.signature = Private.sign(original.get_hash(), private)

        raw = original.pack()
        restored = PositiveGossipTransaction()
        restored.parse(raw)

        self.assertEqual(original.get_hash(), restored.get_hash())
Example #9
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())
Example #10
0
    def fill_with_dummies_and_skips(dag,
                                    prev_hash,
                                    range,
                                    indices_to_skip,
                                    dummy_private=Private.generate()):
        prev_hash_number = dag.get_block_number(prev_hash)
        assert range.start > prev_hash_number, "First block timeslot should be later than anchoring previous block"

        # dummy_private = Private.generate()
        for i in range:
            if i in indices_to_skip: continue
            dummy_time_offset = len(dag.blocks_by_number.get(i, []))
            block = BlockFactory.create_block_with_timestamp(
                [prev_hash], BLOCK_TIME * i + dummy_time_offset)
            signed_block = BlockFactory.sign_block(block, dummy_private)
            dag.add_signed_block(i, signed_block)
            prev_hash = block.get_hash()

        return prev_hash
    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)
Example #12
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
    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_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])
    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])
Example #16
0
    def test_getting_tx_by_hash(self):
        dag = Dag(0)
        private = Private.generate()

        block1 = BlockFactory.create_block_with_timestamp(
            [dag.genesis_block().get_hash()], BLOCK_TIME)
        tx1 = TransactionFactory.create_negative_gossip_transaction(1, private)
        tx2 = TransactionFactory.create_positive_gossip_transaction(
            block1.get_hash(), private)
        tx3 = TransactionFactory.create_penalty_gossip_transaction(
            {tx1.get_hash(): tx2.get_hash()}, private)
        not_appended_tx = TransactionFactory.create_public_key_transaction(
            generated_private=Private.generate(),
            epoch_hash=sha256(b'epoch_hash').digest(),
            validator_index=1,
            node_private=private)
        block1.system_txs.append(tx1)
        block1.system_txs.append(tx2)
        block1.system_txs.append(tx3)

        signed_block1 = BlockFactory.sign_block(block1, private)
        dag.add_signed_block(1, signed_block1)

        self.assertTrue(
            set(dag.transactions_by_hash).issuperset({tx1.get_hash(): tx1}))
        self.assertTrue(
            set(dag.transactions_by_hash).issuperset({tx2.get_hash(): tx2}))
        self.assertTrue(
            set(dag.transactions_by_hash).issuperset({tx3.get_hash(): tx3}))
        self.assertFalse(
            set(dag.transactions_by_hash).issuperset(
                {not_appended_tx.get_hash(): not_appended_tx}))

        # test dag.tx_by_hash getter
        self.assertTrue(dag.get_tx_by_hash(tx1.get_hash()) == tx1)
        self.assertTrue(dag.get_tx_by_hash(tx2.get_hash()) == tx2)
        self.assertTrue(dag.get_tx_by_hash(tx3.get_hash()) == tx3)
    def test_hold_stake(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()
        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()

        block = BlockFactory.create_block_with_timestamp([prev_hash],
                                                         BLOCK_TIME * 9)

        tx = StakeHoldTransaction()
        tx.amount = 1000
        node_new_private = Private.generate()

        tx.pubkey = Private.publickey(node_new_private)
        tx.signature = Private.sign(tx.get_hash(), node_new_private)

        block.system_txs.append(tx)
        signed_block = BlockFactory.sign_block(block, node_private)
        dag.add_signed_block(9, signed_block)

        resulting_validators = permissions.get_validators(block.get_hash())
        pub_keys = []
        for validator in resulting_validators:
            pub_keys.append(validator.public_key)

        self.assertIn(Private.publickey(node_new_private), pub_keys)
    def test_pack_parse_penalty_gossip_transaction(self):
        private = Private.generate()
        original = PenaltyGossipTransaction()
        original.timestamp = Time.get_current_time()
        block = BlockFactory.create_block_with_timestamp(
            [], timestamp=original.timestamp)

        gossip_positive_tx = PositiveGossipTransaction()
        gossip_positive_tx.pubkey = Private.publickey(private)
        gossip_positive_tx.timestamp = Time.get_current_time()
        gossip_positive_tx.block_hash = BlockFactory.sign_block(
            block, private).get_hash()
        gossip_positive_tx.signature = Private.sign(original.get_hash(),
                                                    private)

        gossip_negative_tx = NegativeGossipTransaction()
        gossip_negative_tx.pubkey = Private.publickey(private)
        gossip_negative_tx.timestamp = Time.get_current_time()
        gossip_negative_tx.number_of_block = 47
        gossip_negative_tx.signature = Private.sign(original.get_hash(),
                                                    private)

        original.conflicts = [
            gossip_positive_tx.get_hash(),
            gossip_negative_tx.get_hash()
        ]
        original.signature = Private.sign(original.get_hash(), private)

        original.block_hash = BlockFactory.sign_block(block,
                                                      private).get_hash()

        raw = original.pack()
        restored = PenaltyGossipTransaction()
        restored.parse(raw)

        self.assertEqual(original.get_hash(), restored.get_hash())
Example #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)
Example #20
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}))
Example #21
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())
    def test_remove_from_validators_by_penalty_gossip(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_private = Private.generate()
        genesis_validator_public = initial_validators[9].public_key

        # put to 10 block gossip+ AND gossip- by one node
        block = BlockFactory.create_block_with_timestamp([prev_hash],
                                                         BLOCK_TIME * 10)

        gossip_negative_tx = NegativeGossipTransaction()
        gossip_negative_tx.pubkey = genesis_validator_public
        gossip_negative_tx.timestamp = Time.get_current_time()
        gossip_negative_tx.number_of_block = 5
        gossip_negative_tx.signature = Private.sign(
            gossip_negative_tx.get_hash(), genesis_validator_private)
        # create and add to block negative gossip
        block.system_txs.append(gossip_negative_tx)

        gossip_positive_tx = PositiveGossipTransaction()
        gossip_positive_tx.pubkey = genesis_validator_public
        gossip_positive_tx.timestamp = Time.get_current_time()
        gossip_positive_tx.block_hash = dag.blocks_by_number[5][0].get_hash()
        gossip_positive_tx.signature = Private.sign(
            gossip_positive_tx.get_hash(), genesis_validator_private)
        # create and add to block positive gossip for same number 5 block
        block.system_txs.append(gossip_positive_tx)

        signed_block = BlockFactory.sign_block(block,
                                               genesis_validator_private)
        dag.add_signed_block(10, signed_block)
        prev_hash = block.get_hash()
        # --------------------------------------------------

        # put to 11 block penalty gossip
        block = BlockFactory.create_block_with_timestamp([prev_hash],
                                                         BLOCK_TIME * 11)
        penalty_gossip_tx = PenaltyGossipTransaction()
        penalty_gossip_tx.timestamp = Time.get_current_time()
        penalty_gossip_tx.conflicts = [
            gossip_positive_tx.get_hash(),
            gossip_negative_tx.get_hash()
        ]
        # set genesis validator for sign penalty gossip
        penalty_gossip_tx.signature = Private.sign(
            penalty_gossip_tx.get_hash(), genesis_validator_private)
        block.system_txs.append(penalty_gossip_tx)

        signed_block = BlockFactory.sign_block(block,
                                               genesis_validator_private)
        dag.add_signed_block(11, signed_block)
        prev_hash = block.get_hash()
        # --------------------------------------------------

        # verify that genesis node is steel in validators list
        current_epoch_hash = epoch.get_epoch_hashes()
        # for now we DO NOT NEED to recalculate validators (send genesis block hash)
        resulting_validators = permissions.get_validators(
            current_epoch_hash.get(prev_hash))
        pub_keys = []
        for validator in resulting_validators:
            pub_keys.append(validator.public_key)
        self.assertIn(genesis_validator_public, pub_keys)

        # produce epoch till end
        from chain.params import ROUND_DURATION
        for i in range(12, (ROUND_DURATION * 6 + 4)):
            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()

        # check for new epoch
        self.assertTrue(epoch.is_new_epoch_upcoming(i))
        self.assertTrue(epoch.current_epoch == 2)

        # recalculate validators for last block hash
        resulting_validators = permissions.get_validators(prev_hash)
        pub_keys = []
        for validator in resulting_validators:
            pub_keys.append(validator.public_key)

        self.assertNotIn(genesis_validator_public, pub_keys)
    def test_secret_sharing_rounds(self):
        dag = Dag(0)
        epoch = Epoch(dag)

        dummy_private = Private.generate()

        signers = []
        for i in range(0, ROUND_DURATION + 1):
            signers.append(Private.generate())

        private_keys = []

        block_number = 1
        genesis_hash = dag.genesis_block().get_hash()
        prev_hash = genesis_hash
        signer_index = 0
        for i in Epoch.get_round_range(1, Round.PUBLIC):
            private = Private.generate()
            private_keys.append(private)

            signer = signers[signer_index]
            pubkey_tx = PublicKeyTransaction()
            pubkey_tx.generated_pubkey = Private.publickey(private)
            pubkey_tx.pubkey_index = signer_index
            pubkey_tx.signature = Private.sign(
                pubkey_tx.get_signing_hash(genesis_hash), signer)

            block = Block()
            block.timestamp = i * BLOCK_TIME
            block.prev_hashes = [prev_hash]
            block.system_txs = [pubkey_tx]
            signed_block = BlockFactory.sign_block(block, signer)
            dag.add_signed_block(i, signed_block)
            signer_index += 1
            prev_hash = block.get_hash()

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

        public_keys = []
        for private in private_keys:
            public_keys.append(Private.publickey(private))

        randoms_list = []
        expected_random_pieces = []
        for i in Epoch.get_round_range(1, Round.SECRETSHARE):
            random_bytes = os.urandom(32)
            random_value = int.from_bytes(random_bytes, byteorder='big')
            split_random_tx = SplitRandomTransaction()
            splits = split_secret(random_bytes, 2, 3)
            encoded_splits = encode_splits(splits, public_keys)
            split_random_tx.pieces = encoded_splits
            split_random_tx.pubkey_index = 0
            expected_random_pieces.append(split_random_tx.pieces)
            split_random_tx.signature = Private.sign(pubkey_tx.get_hash(),
                                                     dummy_private)
            block = Block()
            block.timestamp = i * BLOCK_TIME
            block.prev_hashes = [prev_hash]
            block.system_txs = [split_random_tx]
            signed_block = BlockFactory.sign_block(block, dummy_private)
            dag.add_signed_block(i, signed_block)
            randoms_list.append(random_value)
            prev_hash = block.get_hash()

        expected_seed = sum_random(randoms_list)

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

        signer_index = 0
        private_key_index = 0
        raw_private_keys = []
        for i in Epoch.get_round_range(1, Round.PRIVATE):
            private_key_tx = PrivateKeyTransaction()
            private_key_tx.key = Keys.to_bytes(private_keys[private_key_index])
            raw_private_keys.append(private_key_tx.key)
            signer = signers[signer_index]
            block = Block()
            block.system_txs = [private_key_tx]
            block.prev_hashes = [prev_hash]
            block.timestamp = block_number * BLOCK_TIME
            signed_block = BlockFactory.sign_block(block, signer)
            dag.add_signed_block(i, signed_block)
            signer_index += 1
            private_key_index += 1
            prev_hash = block.get_hash()

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

        top_block_hash = dag.get_top_blocks_hashes()[0]

        random_splits = epoch.get_random_splits_for_epoch(top_block_hash)
        self.assertEqual(expected_random_pieces, random_splits)

        restored_randoms = []
        for i in range(0, len(random_splits)):
            random = decode_random(random_splits[i],
                                   Keys.list_from_bytes(raw_private_keys))
            restored_randoms.append(random)

        self.assertEqual(randoms_list, restored_randoms)

        seed = epoch.extract_shared_random(top_block_hash)
        self.assertEqual(expected_seed, seed)
Example #24
0
    def test_confirmations_calculation(self):
        dag = Dag(0)
        private = Private.generate()
        prev_hash = dag.genesis_block().get_hash()
        for i in range(1, 9):
            if i == 5 or i == 7: continue
            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, 5):
            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)

        # first branch check
        confirmations = immutability.calculate_confirmations(
            dag.blocks_by_number[8][0].get_hash())
        self.assertEqual(confirmations, 0)

        skipped_block = SkippedBlock(dag.blocks_by_number[8][0].get_hash(),
                                     backstep_count=1)
        confirmations = immutability.calculate_skipped_block_confirmations(
            skipped_block)
        self.assertEqual(confirmations, 1)

        confirmations = immutability.calculate_confirmations(
            dag.blocks_by_number[6][0].get_hash())
        self.assertEqual(confirmations, 1)

        skipped_block = SkippedBlock(dag.blocks_by_number[6][0].get_hash(),
                                     backstep_count=1)
        confirmations = immutability.calculate_skipped_block_confirmations(
            skipped_block)
        self.assertEqual(confirmations, 2)

        confirmations = immutability.calculate_confirmations(
            dag.blocks_by_number[4][0].get_hash())
        self.assertEqual(confirmations, 2)

        # second branch check
        confirmations = immutability.calculate_confirmations(
            dag.blocks_by_number[4][1].get_hash())
        self.assertEqual(confirmations, 0)

        skipped_block = SkippedBlock(dag.blocks_by_number[4][1].get_hash(),
                                     backstep_count=1)
        confirmations = immutability.calculate_skipped_block_confirmations(
            skipped_block)
        self.assertEqual(confirmations, 1)

        confirmations = immutability.calculate_confirmations(
            dag.blocks_by_number[2][1].get_hash())
        self.assertEqual(confirmations, 1)

        # common ancestor
        # four existing blocks in the following five slots
        confirmations = immutability.calculate_confirmations(
            dag.blocks_by_number[1][0].get_hash())
        self.assertEqual(confirmations, 4)
    def test_commit_reveal(self):
        dag = Dag(0)
        epoch = Epoch(dag)

        private = Private.generate()

        prev_hash = ChainGenerator.fill_with_dummies(
            dag,
            dag.genesis_block().get_hash(),
            Epoch.get_round_range(1, Round.PUBLIC))

        randoms_list = []
        for i in Epoch.get_round_range(1, Round.COMMIT):
            random_value = int.from_bytes(os.urandom(32), byteorder='big')
            randoms_list.append(random_value)

        expected_seed = sum_random(randoms_list)

        reveals = []

        epoch_hash = dag.genesis_block().get_hash()

        for i in Epoch.get_round_range(1, Round.COMMIT):
            rand = randoms_list.pop()
            random_bytes = rand.to_bytes(32, byteorder='big')
            commit, reveal = TestEpoch.create_dummy_commit_reveal(
                random_bytes, epoch_hash)
            commit_block = BlockFactory.create_block_with_timestamp(
                [prev_hash], i * BLOCK_TIME)
            commit_block.system_txs = [commit]
            signed_block = BlockFactory.sign_block(commit_block, private)
            dag.add_signed_block(i, signed_block)
            prev_hash = commit_block.get_hash()
            reveals.append(reveal)

            revealing_key = Keys.from_bytes(reveal.key)
            encrypted_bytes = Public.encrypt(random_bytes,
                                             Private.publickey(revealing_key))
            decrypted_bytes = Private.decrypt(encrypted_bytes, revealing_key)
            # TODO check if encryption decryption can work million times in a row
            self.assertEqual(decrypted_bytes, random_bytes)

            revealed_value = Private.decrypt(commit.rand, revealing_key)
            self.assertEqual(revealed_value, random_bytes)

        # self.assertEqual(len(reveals), ROUND_DURATION)

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

        for i in Epoch.get_round_range(1, Round.REVEAL):
            reveal_block = BlockFactory.create_block_with_timestamp(
                [prev_hash], i * BLOCK_TIME)
            reveal_block.system_txs = [reveals.pop()]
            signed_block = BlockFactory.sign_block(reveal_block, private)
            dag.add_signed_block(i, signed_block)
            prev_hash = reveal_block.get_hash()

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

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

        seed = epoch.reveal_commited_random(prev_hash)
        self.assertEqual(expected_seed, seed)
Example #26
0
    def sign_block(self, current_block_number):
        current_round_type = self.epoch.get_round_by_block_number(
            current_block_number)
        epoch_number = Epoch.get_epoch_number(current_block_number)

        system_txs = self.get_system_transactions_for_signing(
            current_round_type)
        payment_txs = self.get_payment_transactions_for_signing(
            current_block_number)

        tops = self.dag.get_top_blocks_hashes()
        chosen_top = self.dag.get_longest_chain_top(tops)
        conflicting_tops = [top for top in tops if top != chosen_top]

        current_top_blocks = [
            chosen_top
        ] + conflicting_tops  # first link in dag is not considered conflict, the rest is.

        if self.behaviour.off_malicious_links_to_wrong_blocks:
            current_top_blocks = []
            all_hashes = list(self.dag.blocks_by_hash.keys())
            for _ in range(random.randint(1, 3)):
                block_hash = random.choice(all_hashes)
                current_top_blocks.append(block_hash)

            self.logger.info(
                "Maliciously connecting block at slot %s to random hashes",
                current_block_number)

        block = BlockFactory.create_block_dummy(current_top_blocks)
        block.system_txs = system_txs
        block.payment_txs = payment_txs
        signed_block = BlockFactory.sign_block(block,
                                               self.block_signer.private_key)

        if self.behaviour.malicious_block_broadcast_delay > 0:
            self.behaviour.block_to_delay_broadcasting = signed_block
            return  # don't do broadcasting, wait a few timeslots1

        self.dag.add_signed_block(current_block_number, signed_block)
        self.utxo.apply_payments(payment_txs)
        self.conflict_watcher.on_new_block_by_validator(
            block.get_hash(), epoch_number, self.node_pubkey)

        if not self.behaviour.transport_cancel_block_broadcast:  # behaviour flag for cancel block broadcast
            self.logger.debug("Broadcasting signed block number %s",
                              current_block_number)
            self.network.broadcast_block(self.node_id, signed_block.pack())
        else:
            self.logger.info(
                "Created but maliciously skipped broadcasted block")

        if self.behaviour.malicious_excessive_block_count > 0:
            additional_block_timestamp = block.timestamp + 1
            additional_block = BlockFactory.create_block_with_timestamp(
                current_top_blocks, additional_block_timestamp)
            additional_block.system_txs = block.system_txs
            additional_block.payment_txs = block.payment_txs
            signed_add_block = BlockFactory.sign_block(
                additional_block, self.block_signer.private_key)
            self.dag.add_signed_block(current_block_number, signed_add_block)
            self.conflict_watcher.on_new_block_by_validator(
                signed_add_block.get_hash(), epoch_number,
                self.node_pubkey)  #mark our own conflict for consistency
            self.logger.info("Sending additional block")
            self.network.broadcast_block(self.node_id, signed_add_block.pack())
            self.behaviour.malicious_excessive_block_count -= 1
    def test_release_stake(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()

        block = BlockFactory.create_block_with_timestamp([prev_hash],
                                                         BLOCK_TIME * 9)

        # create new node for stake hold
        new_node_private = Private.generate()
        new_node_public = Private.publickey(new_node_private)

        # create transaction for stake hold for new node
        tx_hold = StakeHoldTransaction()
        tx_hold.amount = 2000
        tx_hold.pubkey = Keys.to_bytes(new_node_public)
        tx_hold.signature = Private.sign(tx_hold.get_hash(), new_node_private)

        # append signed stake hold transaction
        block.system_txs.append(tx_hold)

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

        resulting_validators = permissions.get_validators(block.get_hash())
        pub_keys = []
        for validator in resulting_validators:
            pub_keys.append(validator.public_key)
        self.assertIn(new_node_public, pub_keys)

        # add blocks for new epoch
        for i in range(10, 18):
            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()

        # create stake release transaction for new stakeholder
        tx_release = StakeReleaseTransaction()
        tx_release.pubkey = Keys.to_bytes(new_node_public)
        tx_release.signature = Private.sign(tx_hold.get_hash(),
                                            new_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)

        # verify that new stake holder now is NOT in validators list (after stake release transaction signed by holder)
        resulting_validators = permissions.get_validators(block.get_hash())
        pub_keys = []
        for validator in resulting_validators:
            pub_keys.append(validator.public_key)
        self.assertNotIn(new_node_public, pub_keys)