Пример #1
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])
Пример #2
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)
Пример #3
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)
Пример #4
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)
Пример #5
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])
 def create_positive_gossip_transaction(block_hash, node_private):
     tx = PositiveGossipTransaction()
     tx.timestamp = Time.get_current_time()
     tx.block_hash = block_hash
     tx.pubkey = Private.publickey(node_private)
     tx.signature = Private.sign(tx.get_hash(), node_private)
     return tx
 def create_negative_gossip_transaction(number_of_block, node_private):
     tx = NegativeGossipTransaction()
     tx.timestamp = Time.get_current_time()
     tx.number_of_block = number_of_block
     tx.pubkey = Private.publickey(node_private)
     tx.signature = Private.sign(tx.get_hash(), node_private)
     return tx
 def create_public_key_transaction(generated_private, epoch_hash,
                                   validator_index, node_private):
     tx = PublicKeyTransaction()
     tx.generated_pubkey = Private.publickey(generated_private)
     tx.pubkey_index = validator_index
     tx.signature = Private.sign(tx.get_signing_hash(epoch_hash),
                                 node_private)
     return tx
 def create_payment_transaction(from_tx, amount, to, node_private):
     tx = PaymentTransaction()
     tx.from_tx = from_tx
     tx.amount = amount
     tx.to = to
     tx.pubkey = Private.publickey(node_private)
     tx.signature = Private.sign(tx.get_hash(), node_private)
     return tx
Пример #10
0
 def get_payment_transactions_for_signing(self, block_number):
     node_public = Private.publickey(self.block_signer.private_key)
     pseudo_address = sha256(node_public).digest()
     block_reward = TransactionFactory.create_block_reward(
         pseudo_address, block_number)
     block_reward_hash = block_reward.get_hash()
     self.owned_utxos.append(block_reward_hash)
     payment_txs = [block_reward] + self.mempool.pop_payment_transactions()
     return payment_txs
Пример #11
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)
Пример #12
0
    def extract_shared_random(self, block_hash):
        if block_hash == self.dag.genesis_block().get_hash():
            return 0

        private_keys = self.get_private_keys_for_epoch(block_hash)
        public_keys = self.get_public_keys_for_epoch(block_hash)
        published_private_keys = self.filter_out_skipped_public_keys(
            private_keys, public_keys)
        random_pieces_list = self.get_random_splits_for_epoch(block_hash)

        # self.log("pubkeys")
        # for _, public_key in public_keys.items():
        # self.log(Keys.to_visual_string(public_key))
        # self.log("privkeys converted")
        private_key_count = 0  # amount of sent keys
        matching_keys_count = 0  # amount of keys which have matching pubkeys
        for key in published_private_keys:
            if not key:
                # self.log("None")
                continue
            pubkey = Private.publickey(key)
            # self.log(Keys.to_visual_string(pubkey))
            private_key_count += 1
            if Keys.to_bytes(pubkey) in public_keys.values():
                matching_keys_count += 1

        pubkey_count = len(public_keys)
        self.log("pubkey count", pubkey_count, "privkey count",
                 private_key_count, "of them matching", matching_keys_count)

        half_of_pubkeys = int(pubkey_count / 2) + 1
        half_of_privkeys = int(private_key_count / 2) + 1

        # TODO we should have a special handling for when not enough keys was sent for each round
        assert pubkey_count > 1, "Not enough public keys to decrypt random"
        assert private_key_count > 1, "Not enough private keys to decrypt random"
        assert pubkey_count >= half_of_privkeys, "Not enough public keys to decrypt random"
        assert private_key_count >= half_of_pubkeys, "Not enough private keys to decrypt random"
        assert matching_keys_count >= half_of_pubkeys, "Not enough matching keys in epoch"
        assert matching_keys_count >= half_of_privkeys, "Not enough matching keys in epoch"

        ordered_private_keys_count = len(
            private_keys)  # total amount of both sent and unsent keys
        randoms_list = []
        for random_pieces in random_pieces_list:
            assert ordered_private_keys_count >= len(
                random_pieces
            ), "Amount of splits must match amount of public keys"
            random = decode_random(
                random_pieces, Keys.list_from_bytes(published_private_keys))
            randoms_list.append(random)

        seed = sum_random(randoms_list)
        return seed
Пример #13
0
 def filter_out_skipped_public_keys(private_keys, public_keys):
     filtered_private_keys = []
     for private_key in private_keys:
         if private_key == None:
             filtered_private_keys.append(None)
         else:
             expected_public = Private.publickey(
                 Keys.from_bytes(private_key))
             if Keys.to_bytes(expected_public) in public_keys.values():
                 filtered_private_keys.append(private_key)
     return filtered_private_keys
Пример #14
0
    def test_pack_parse_stakerelease_transaction(self):
        private = Private.generate()
        original = StakeReleaseTransaction()
        original.pubkey = Private.publickey(private)
        original.signature = Private.sign(original.get_hash(),
                                          Private.generate())

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

        self.assertEqual(original.get_hash(), restored.get_hash())
Пример #15
0
    def test_pack_parse_penalty_transaction(self):
        original = PenaltyTransaction()
        original.violator_pubkey = Private.publickey(Private.generate())
        original.conflicts = [os.urandom(32), os.urandom(32), os.urandom(32)]
        original.signature = Private.sign(original.get_hash(),
                                          Private.generate())

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

        self.assertEqual(original.get_hash(), restored.get_hash())
Пример #16
0
    def test_pack_parse_stakehold_transaction(self):
        private = Private.generate()
        original = StakeHoldTransaction()
        original.amount = 1000
        original.pubkey = Private.publickey(private)
        original.signature = Private.sign(original.get_hash(), private)

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

        self.assertEqual(original.get_hash(), restored.get_hash())
    def test_parse_pack_gossip_negative(self):
        private = Private.generate()
        original = NegativeGossipTransaction()
        original.pubkey = Private.publickey(private)
        original.timestamp = Time.get_current_time()
        original.number_of_block = 47
        original.signature = Private.sign(original.get_hash(), private)

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

        self.assertEqual(original.get_hash(), restored.get_hash())
    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())
    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())
    def test_encryption_and_decryption(self):
        private_keys = []
        public_keys = []
        for i in range(0, 5):
            private = Private.generate()
            private_keys.append(private)
            public_keys.append(Private.publickey(private))

        raw_private_keys = Keys.list_to_bytes(private_keys)
        decoded_private_keys = Keys.list_from_bytes(raw_private_keys)

        random_bytes = os.urandom(32)
        random_value = int.from_bytes(random_bytes, byteorder='big')
        splits = split_secret(random_bytes, 3, 5)
        encoded_splits = encode_splits(splits, public_keys)
        decoded_random = decode_random(encoded_splits, decoded_private_keys)

        self.assertEqual(random_value, decoded_random)
    def test_decryption_failure(self):
        private_keys = []
        public_keys = []
        for i in range(0, 5):
            private = Private.generate()
            private_keys.append(private)
            public_keys.append(Private.publickey(private))

        raw_private_keys = Keys.list_to_bytes(private_keys)
        decoded_private_keys = Keys.list_from_bytes(raw_private_keys)

        random_bytes = os.urandom(32)
        random_value = int.from_bytes(random_bytes, byteorder='big')
        splits = split_secret(random_bytes, 3, 5)
        encoded_splits = encode_splits(splits, public_keys)
        encoded_splits[2] = os.urandom(len(
            encoded_splits[2]))  #corrupt one of the splits
        encoded_splits[4] = os.urandom(len(
            encoded_splits[4]))  #corrupt another split
        decoded_random = decode_random(encoded_splits, decoded_private_keys)

        self.assertEqual(random_value, decoded_random)
Пример #23
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)
Пример #24
0
    def __init__(self,
                 genesis_creation_time,
                 node_id,
                 network,
                 block_signer=BlockSigner(Private.generate()),
                 validators=Validators(),
                 behaviour=Behaviour(),
                 logger=DummyLogger()):
        self.logger = logger
        self.dag = Dag(genesis_creation_time)
        self.epoch = Epoch(self.dag)
        self.epoch.set_logger(self.logger)
        self.permissions = Permissions(self.epoch, validators)
        self.mempool = Mempool()
        self.utxo = Utxo(self.logger)
        self.conflict_watcher = ConflictWatcher(self.dag)
        self.behaviour = behaviour

        self.block_signer = block_signer
        self.node_pubkey = Private.publickey(block_signer.private_key)
        self.logger.info("Public key is %s",
                         Keys.to_visual_string(self.node_pubkey))
        self.network = network
        self.node_id = node_id
        self.epoch_private_keys = []  # TODO make this single element
        # self.epoch_private_keys where first element is era number, and second is key to reveal commited random
        self.reveals_to_send = {}
        self.sent_shares_epochs = []  # epoch hashes of secret shares
        self.last_expected_timeslot = 0
        self.last_signed_block_number = 0
        self.tried_to_sign_current_block = False
        self.owned_utxos = []
        self.terminated = False

        self.blocks_buffer = [
        ]  # uses while receive block and do not have its ancestor in local dag (before verify)
    def validate_private_transactions_in_block(self, block, current_round):
        private_key_transactions = []
        for tx in block.system_txs:
            if isinstance(tx, PrivateKeyTransaction):
                private_key_transactions.append(tx)

        private_key_transactions_count_in_block = len(private_key_transactions)

        if current_round != Round.PRIVATE:
            if private_key_transactions_count_in_block > 0:
                raise AcceptionException(
                    "PrivateKeyTransaction was found in round " +
                    current_round.name)

            return

        if private_key_transactions_count_in_block == 0:
            raise AcceptionException(
                "Block has no PrivateKeyTransaction in private round!")

        elif private_key_transactions_count_in_block > 1:
            raise AcceptionException(
                "Block has more than one PrivateKeyTransaction!")

        return  # this check is too slow and I'm not sure if it's needed at all

        private_key = private_key_transactions[0].key
        expected_public = Private.publickey(private_key)
        epoch_hashes = self.epoch.get_epoch_hashes()

        for top, _epoch_hash in epoch_hashes.items():
            public_keys = self.epoch.get_public_keys_for_epoch(top)
            if not Keys.to_bytes(expected_public) in public_keys.values():
                raise AcceptionException(
                    "No corresponding public key was found for private key in PrivateKeyTransaction!"
                )
    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)
    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)
 def create_stake_release_transaction(node_private):
     tx = StakeReleaseTransaction()
     tx.pubkey = Private.publickey(node_private)
     tx.signature = Private.sign(tx.get_hash(), node_private)
     return tx
    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)
    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)