def test_dont_revert_block_low_weight(self):
        """ A conflict transaction will be propagated and voided.
        A new block with low weight will verify it, which won't be enough to flip to executed.
        So, it will remain voided.
        """
        self.assertEqual(len(self.genesis_blocks), 1)
        manager = self.create_peer('testnet', tx_storage=self.tx_storage)

        # Mine a few blocks in a row with no transaction but the genesis
        blocks = add_new_blocks(manager, 3, advance_clock=15)
        add_blocks_unlock_reward(manager)

        # Add some transactions between blocks
        add_new_transactions(manager, 5, advance_clock=15)

        # Create a double spending transaction.
        conflicting_tx = add_new_double_spending(manager,
                                                 use_same_parents=True)

        # Add a few transactions.
        add_new_transactions(manager, 10, advance_clock=15)

        meta = conflicting_tx.get_metadata()
        self.assertEqual(meta.voided_by, {conflicting_tx.hash})
        for parent_hash in conflicting_tx.parents:
            self.assertNotIn(parent_hash, meta.conflict_with)

        # These blocks will be voided later.
        add_new_blocks(manager, 2, advance_clock=15)

        # This block verifies the conflicting transaction and has a low weight.
        # So, it is not enough to revert and this block will be voided as well.
        b0 = manager.generate_mining_block()
        b0.parents = [
            blocks[-1].hash, conflicting_tx.hash, conflicting_tx.parents[0]
        ]
        b0.resolve()
        b0.verify()
        manager.propagate_tx(b0, fails_silently=False)

        b1 = add_new_block(manager, advance_clock=15)
        b2 = add_new_block(manager, advance_clock=15)

        # dot = GraphvizVisualizer(manager.tx_storage, include_verifications=True, include_funds=True).dot()
        # dot.render('dot1')

        self.assertNotEqual(b1.parents[0], b0.hash)
        self.assertEqual(b2.parents[0], b1.hash)

        meta = conflicting_tx.get_metadata()
        self.assertEqual(meta.voided_by, {conflicting_tx.hash})

        b0_meta = b0.get_metadata()
        self.assertEqual(b0_meta.voided_by, {b0.hash, conflicting_tx.hash})

        self.assertConsensusValid(manager)
    def test_dont_revert_block_high_weight_verify_both(self):
        """ A conflicting transaction will be propagated and voided. But the block with high weight
        verifies both the conflicting transactions, so this block will always be voided.
        """
        self.assertEqual(len(self.genesis_blocks), 1)
        manager = self.create_peer('testnet', tx_storage=self.tx_storage)

        # Mine a few blocks in a row with no transaction but the genesis
        add_new_blocks(manager, 3, advance_clock=15)
        add_blocks_unlock_reward(manager)

        # Add some transactions between blocks
        add_new_transactions(manager, 5, advance_clock=15)

        # Create a double spending transaction.
        conflicting_tx = add_new_double_spending(manager,
                                                 use_same_parents=True)

        # Add a few transactions.
        add_new_transactions(manager, 10, advance_clock=15)

        meta = conflicting_tx.get_metadata()
        self.assertEqual(meta.voided_by, {conflicting_tx.hash})
        for parent_hash in conflicting_tx.parents:
            self.assertNotIn(parent_hash, meta.conflict_with)

        # Add two blocks.
        blocks2 = add_new_blocks(manager, 2, advance_clock=15)

        # This block verifies the conflicting transaction and has a high weight.
        b0 = manager.generate_mining_block()
        b0.parents = [
            b0.parents[0], conflicting_tx.hash, conflicting_tx.parents[0]
        ]
        b0.weight = 10
        b0.resolve()
        b0.verify()
        manager.propagate_tx(b0, fails_silently=False)

        b1 = add_new_block(manager, advance_clock=15)
        b2 = add_new_block(manager, advance_clock=15)

        # dot = GraphvizVisualizer(manager.tx_storage, include_verifications=True, include_funds=True).dot()
        # dot.render('dot3')

        self.assertNotEqual(b1.parents[0], b0.hash)
        self.assertEqual(b2.parents[0], b1.hash)

        meta = conflicting_tx.get_metadata()
        self.assertEqual(meta.voided_by, {conflicting_tx.hash})

        for block in blocks2:
            meta = block.get_metadata()
            self.assertIsNone(meta.voided_by)

        self.assertConsensusValid(manager)
    def test_dont_revert_block_high_weight_transaction_verify_other(self):
        """ A conflict transaction will be propagated and voided. But this transaction
        verifies its conflicting transaction. So, its accumulated weight will always be smaller
        than the others and it will never be executed.
        """
        self.assertEqual(len(self.genesis_blocks), 1)
        manager = self.create_peer('testnet', tx_storage=self.tx_storage)

        # Mine a few blocks in a row with no transaction but the genesis
        blocks = add_new_blocks(manager, 3, advance_clock=15)
        add_blocks_unlock_reward(manager)

        # Add some transactions between blocks
        txs = add_new_transactions(manager, 5, advance_clock=15)

        # Create a double spending transaction.
        conflicting_tx = add_new_double_spending(manager, tx=txs[-1])
        meta = conflicting_tx.get_metadata()
        self.assertEqual(len(meta.conflict_with), 1)
        self.assertIn(list(meta.conflict_with)[0], conflicting_tx.parents)

        # Add a few transactions.
        add_new_transactions(manager, 10, advance_clock=15)

        meta = conflicting_tx.get_metadata()
        self.assertEqual(meta.voided_by, {conflicting_tx.hash})

        # These blocks will be voided later.
        blocks2 = add_new_blocks(manager, 2, advance_clock=15)

        # This block verifies the conflicting transaction and has a high weight.
        tb0 = manager.make_custom_block_template(
            blocks[-1].hash, [conflicting_tx.hash, conflicting_tx.parents[0]])
        b0 = tb0.generate_mining_block(manager.rng, storage=manager.tx_storage)
        b0.weight = 10
        b0.resolve()
        b0.verify()
        manager.propagate_tx(b0, fails_silently=False)

        b1 = add_new_block(manager, advance_clock=15)
        b2 = add_new_block(manager, advance_clock=15)

        # dot = GraphvizVisualizer(manager.tx_storage, include_verifications=True, include_funds=True).dot()
        # dot.render('dot2')

        self.assertNotEqual(b1.parents[0], b0.hash)
        self.assertEqual(b2.parents[0], b1.hash)

        meta = conflicting_tx.get_metadata()
        self.assertEqual(meta.voided_by, {conflicting_tx.hash})

        for block in blocks2:
            meta = block.get_metadata()
            self.assertIsNone(meta.voided_by)

        self.assertConsensusValid(manager)
    def test_topological_sort_dfs(self):
        _set_test_mode(TestMode.TEST_ALL_WEIGHT)
        add_new_blocks(self.manager, 11, advance_clock=1)
        tx = add_new_transactions(self.manager, 1, advance_clock=1)[0]

        total = 0
        for tx in self.cache_storage._topological_sort_dfs(root=tx,
                                                           visited=dict()):
            total += 1
        self.assertEqual(total, 5)
Beispiel #5
0
    def test_token(self):
        resource = StubSite(TokenResource(self.manager))

        # test invalid token id
        response = yield resource.get('thin_wallet/token',
                                      {b'id': 'vvvv'.encode()})
        data = response.json_value()
        self.assertFalse(data['success'])

        # test missing token id
        response = yield resource.get('thin_wallet/token')
        data = response.json_value()
        self.assertFalse(data['success'])

        # test unknown token id
        unknown_uid = '00000000228ed1dd74a2e1b920c1d64bf81dc63875dce4fac486001073b45a27'.encode(
        )
        response = yield resource.get('thin_wallet/token',
                                      {b'id': unknown_uid})
        data = response.json_value()
        self.assertFalse(data['success'])

        # test success case
        add_new_blocks(self.manager, 1, advance_clock=1)
        add_blocks_unlock_reward(self.manager)
        token_name = 'MyTestToken'
        token_symbol = 'MTT'
        amount = 150
        tx = create_tokens(self.manager,
                           mint_amount=amount,
                           token_name=token_name,
                           token_symbol=token_symbol)
        token_uid = tx.tokens[0]
        response = yield resource.get('thin_wallet/token',
                                      {b'id': token_uid.hex().encode()})
        data = response.json_value()
        self.assertTrue(data['success'])
        self.assertEqual(len(data['mint']), 1)
        self.assertEqual(len(data['melt']), 1)
        self.assertEqual(data['mint'][0]['tx_id'], tx.hash_hex)
        self.assertEqual(data['melt'][0]['tx_id'], tx.hash_hex)
        self.assertEqual(data['mint'][0]['index'], 1)
        self.assertEqual(data['melt'][0]['index'], 2)
        self.assertEqual(data['total'], amount)
        self.assertEqual(data['name'], token_name)
        self.assertEqual(data['symbol'], token_symbol)

        # test no wallet index
        manager2 = self.create_peer(self.network, unlock_wallet=True)
        resource2 = StubSite(TokenResource(manager2))
        response2 = yield resource2.get('thin_wallet/token')
        data2 = response2.json_value()
        self.assertEqual(response2.responseCode, 503)
        self.assertFalse(data2['success'])
Beispiel #6
0
    def setUp(self):
        super().setUp()

        self.network = 'testnet'
        self.manager = self.create_peer(self.network, unlock_wallet=True)

        add_new_blocks(self.manager, 1, advance_clock=1)
        add_blocks_unlock_reward(self.manager)
        self.tx = add_new_transactions(self.manager, 1, advance_clock=1)[0]

        self.parser = create_parser()
    def test_single_chain(self):
        """ All new blocks belong to case (i).
        """
        self.assertEqual(len(self.genesis_blocks), 1)
        manager = self.create_peer('testnet', tx_storage=self.tx_storage)

        # The initial score is the sum of the genesis
        score = self.genesis_blocks[0].weight
        for tx in self.genesis_txs:
            score = sum_weights(score, tx.weight)

        # Mine 100 blocks in a row with no transaction but the genesis
        blocks = add_new_blocks(manager, 100, advance_clock=15)
        for i, block in enumerate(blocks):
            meta = block.get_metadata(force_reload=True)
            score = sum_weights(score, block.weight)
            self.assertAlmostEqual(score, meta.score)

        # Add some transactions between blocks
        txs = add_new_transactions(manager, 30, advance_clock=15)
        for tx in txs:
            score = sum_weights(score, tx.weight)

        # Mine 50 more blocks in a row with no transactions between them
        blocks = add_new_blocks(manager, 50)
        for i, block in enumerate(blocks):
            meta = block.get_metadata()
            score = sum_weights(score, block.weight)
            self.assertAlmostEqual(score, meta.score)
            self.assertAlmostEqual(
                manager.consensus_algorithm.block_algorithm.calculate_score(
                    block), meta.score)

        # Mine 15 more blocks with 10 transactions between each block
        for _ in range(15):
            txs = add_new_transactions(manager, 10, advance_clock=15)
            for tx in txs:
                score = sum_weights(score, tx.weight)

            blocks = add_new_blocks(manager, 1)
            for i, block in enumerate(blocks):
                meta = block.get_metadata()
                score = sum_weights(score, block.weight)
                self.assertAlmostEqual(score, meta.score)
                self.assertAlmostEqual(
                    manager.consensus_algorithm.block_algorithm.
                    calculate_score(block), meta.score)

        self.assertConsensusValid(manager)
Beispiel #8
0
 def test_reward_lock(self):
     from hathor.transaction.exceptions import RewardLocked
     # add block with a reward we can spend
     reward_block = self.manager.generate_mining_block(address=get_address_from_public_key(self.genesis_public_key))
     reward_block.resolve()
     self.assertTrue(self.manager.propagate_tx(reward_block))
     # reward cannot be spent while not enough blocks are added
     for _ in range(settings.REWARD_SPEND_MIN_BLOCKS):
         tx = self._spend_reward_tx(self.manager, reward_block)
         with self.assertRaises(RewardLocked):
             tx.verify()
         add_new_blocks(self.manager, 1, advance_clock=1)
     # now it should be spendable
     tx = self._spend_reward_tx(self.manager, reward_block)
     self.assertTrue(self.manager.propagate_tx(tx, fails_silently=False))
Beispiel #9
0
    def test_script_too_big(self) -> Generator:
        self.manager.wallet.unlock(b'MYPASS')
        add_new_blocks(self.manager, 5, advance_clock=15)
        add_blocks_unlock_reward(self.manager)
        tx = self.get_tx()

        # Invalid tx (output script is too long)
        tx.outputs[0].script = b'*' * (settings.PUSHTX_MAX_OUTPUT_SCRIPT_SIZE +
                                       1)
        tx.resolve()
        tx_hex = tx.get_struct().hex()
        response = yield self.push_tx({'hex_tx': tx_hex})
        data = response.json_value()
        self.assertFalse(data['success'])
        self.assertEqual('Transaction is non standard.', data['message'])
Beispiel #10
0
    def test_non_standard_script(self) -> Generator:
        self.manager.wallet.unlock(b'MYPASS')
        add_new_blocks(self.manager, 5, advance_clock=15)
        add_blocks_unlock_reward(self.manager)
        tx = self.get_tx()

        # Invalid tx (output script is too long)
        tx.outputs[0].script = b'*' * 5
        tx.resolve()
        tx_hex = tx.get_struct().hex()
        response = yield self.push_tx({'hex_tx': tx_hex})
        data = response.json_value()
        self.assertFalse(data['success'])
        expected = 'Transaction is non standard.'
        self.assertEqual(expected, data['message'])
Beispiel #11
0
    def test_get_one(self):
        genesis_tx = next(x for x in self.manager.tx_storage.get_all_genesis()
                          if x.is_block)
        response_success = yield self.web.get(
            "transaction", {b'id': bytes(genesis_tx.hash.hex(), 'utf-8')})
        data_success = response_success.json_value()
        self.assertTrue(data_success['success'])
        dict_test = genesis_tx.to_json(decode_script=True)
        dict_test['raw'] = genesis_tx.get_struct().hex()
        dict_test['nonce'] = str(dict_test['nonce'])
        if genesis_tx.is_block:
            dict_test['height'] = genesis_tx.calculate_height()
        self.assertEqual(data_success['tx'], dict_test)

        # Test sending hash that does not exist
        response_error1 = yield self.web.get(
            "transaction", {
                b'id':
                b'000000831cff82fa730cbdf8640fae6c130aab1681336e2f8574e314a5533848'
            })
        data_error1 = response_error1.json_value()
        self.assertFalse(data_error1['success'])

        # Test sending invalid hash
        response_error2 = yield self.web.get(
            "transaction", {
                b'id':
                b'000000831cff82fa730cbdf8640fae6c130aab1681336e2f8574e314a553384'
            })
        data_error2 = response_error2.json_value()
        self.assertFalse(data_error2['success'])

        # Adding blocks to have funds
        add_new_blocks(self.manager, 2, advance_clock=1)
        add_blocks_unlock_reward(self.manager)
        tx = add_new_transactions(self.manager, 1)[0]

        tx2 = Transaction.create_from_struct(tx.get_struct())
        tx2.parents = [tx.parents[1], tx.parents[0]]
        tx2.resolve()

        self.manager.propagate_tx(tx2)

        # Now we get a tx with conflict, voided_by and twin
        response_conflict = yield self.web.get(
            "transaction", {b'id': bytes(tx2.hash.hex(), 'utf-8')})
        data_conflict = response_conflict.json_value()
        self.assertTrue(data_conflict['success'])
Beispiel #12
0
    def test_get(self):

        # Success empty mempool
        response1 = yield self.web.get("mempool")
        data1 = response1.json_value()
        self.assertTrue(data1['success'])
        self.assertEqual(data1['transactions'], [])

        # Success mempool with single TX
        txs2 = add_new_transactions(self.manager, 1, advance_clock=1)
        response2 = yield self.web.get("mempool")
        data2 = response2.json_value()
        self.assertTrue(data2['success'])
        self.assertEqual(data2['transactions'],
                         list(map(lambda t: t.hash.hex(), txs2)))

        # Success mempool with multiple TX
        txs3 = add_new_transactions(self.manager, 2, advance_clock=1)
        response3 = yield self.web.get("mempool")
        data3 = response3.json_value()
        self.assertTrue(data3['success'])
        self.assertEqual(data3['transactions'],
                         list(map(lambda t: t.hash.hex(), txs2 + txs3)))

        # add block to confirm previous txs
        add_new_blocks(self.manager, 1, advance_clock=1)

        # and next call will not have previous mempool
        txs4 = add_new_transactions(self.manager, 2, advance_clock=1)
        response4 = yield self.web.get("mempool")
        data4 = response4.json_value()
        self.assertTrue(data4['success'])
        self.assertEqual(data4['transactions'],
                         list(map(lambda t: t.hash.hex(), txs4)))

        # add block to confirm previous txs
        add_new_blocks(self.manager, 1, advance_clock=1)

        # Add more than api limit and check truncated return
        add_new_transactions(self.manager,
                             settings.MEMPOOL_API_TX_LIMIT + 1,
                             advance_clock=1)
        response5 = yield self.web.get("mempool")
        data5 = response5.json_value()
        self.assertTrue(data5['success'])
        # default limit is 100
        self.assertEqual(len(data5['transactions']),
                         settings.MEMPOOL_API_TX_LIMIT)
    def test_regular_block_template(self):
        manager = self.create_peer('testnet', tx_storage=self.tx_storage)

        # add 100 blocks
        blocks = add_new_blocks(manager, 100, advance_clock=15)

        block_templates = manager.get_block_templates()
        self.assertEqual(len(block_templates), 1)
        self.assertEqual(
            block_templates[0],
            BlockTemplate(
                versions={0, 3},
                reward=settings.INITIAL_TOKEN_UNITS_PER_BLOCK * 100,
                weight=1.0,
                timestamp_now=int(manager.reactor.seconds()),
                timestamp_min=blocks[-1].timestamp + 1,
                timestamp_max=blocks[-1].timestamp +
                settings.MAX_DISTANCE_BETWEEN_BLOCKS - 1,
                # parents=[blocks[-1].hash, self.genesis_txs[-1].hash, self.genesis_txs[-2].hash],
                parents=block_templates[0].parents,
                parents_any=[],
                height=101,  # genesis is 0
                score=sum_weights(blocks[-1].get_metadata().score, 1.0),
            ))

        self.assertConsensusValid(manager)
Beispiel #14
0
    def setUp(self):
        super().setUp()
        self.tx_storage = ModifiedTransactionMemoryStorage()
        self.network = 'testnet'
        self.manager = self.create_peer(self.network,
                                        tx_storage=self.tx_storage)

        self.all_hashes = set()
        for tx in self.manager.tx_storage.get_all_transactions():
            self.all_hashes.add(tx.hash)

        # generate blocks and transactions where blk1 is spent by tx1
        self.blk1 = add_new_block(self.manager, advance_clock=15)
        self.block_list = add_blocks_unlock_reward(self.manager)

        self.tx_list = add_new_transactions(self.manager, 5, advance_clock=15)
        self.tx1 = self.tx_list[0]
        self.assertTrue(self.tx1.inputs[0].tx_id == self.blk1.hash)

        self.block_list2 = add_new_blocks(self.manager, 8, advance_clock=15)

        # collect all hashes
        self.all_hashes.add(self.blk1.hash)
        self.all_hashes.update(x.hash for x in self.block_list)
        self.all_hashes.update(x.hash for x in self.tx_list)
        self.all_hashes.update(x.hash for x in self.block_list2)
        def setUp(self):
            super().setUp()

            self.network = 'testnet'
            self.manager = self.create_peer(self.network, unlock_wallet=True)
            self.tx_storage = self.manager.tx_storage

            data = b'This is a test block.'
            self.blocks = add_new_blocks(self.manager, 3, advance_clock=15, block_data=data)

            address = self.get_address(0)
            value = 100

            outputs = [
                WalletOutputInfo(address=decode_address(address), value=int(value), timelock=None)
            ]

            self.tx1 = self.manager.wallet.prepare_transaction_compute_inputs(Transaction, outputs)
            self.tx1.weight = 10
            self.tx1.parents = self.manager.get_new_tx_parents()
            self.tx1.timestamp = int(self.clock.seconds())
            self.tx1.resolve()
            self.manager.propagate_tx(self.tx1)

            # Change of parents only, so it's a twin.
            # With less weight, so the balance will continue because tx1 will be the winner
            self.tx2 = Transaction.create_from_struct(self.tx1.get_struct())
            self.tx2.parents = [self.tx1.parents[1], self.tx1.parents[0]]
            self.tx2.weight = 9
            self.tx2.resolve()

            # Propagate a conflicting twin transaction
            self.manager.propagate_tx(self.tx2)
    def setUp(self):
        super().setUp()

        self.network = 'testnet'
        self.manager = self.create_peer(self.network, unlock_wallet=True)

        blocks = add_new_blocks(self.manager, 3, advance_clock=15)
        self.blocks_tokens = [
            sum(txout.value for txout in blk.outputs) for blk in blocks
        ]

        address = self.get_address(0)
        value = 100

        self.initial_balance = sum(self.blocks_tokens[:3]) - 100

        outputs = [
            WalletOutputInfo(address=decode_address(address),
                             value=int(value),
                             timelock=None)
        ]

        add_blocks_unlock_reward(self.manager)

        self.tx1 = self.manager.wallet.prepare_transaction_compute_inputs(
            Transaction, outputs)
        self.tx1.weight = 10
        self.tx1.parents = self.manager.get_new_tx_parents()
        self.tx1.timestamp = int(self.clock.seconds())
        self.tx1.resolve()
        self.manager.propagate_tx(self.tx1)
        self.run_to_completion()
Beispiel #17
0
    def test_twin_tx(self):
        add_new_blocks(self.manager, 5, advance_clock=15)
        add_blocks_unlock_reward(self.manager)

        address = self.get_address(0)
        value1 = 100
        value2 = 101

        outputs = [
            WalletOutputInfo(address=decode_address(address),
                             value=int(value1),
                             timelock=None),
            WalletOutputInfo(address=decode_address(address),
                             value=int(value2),
                             timelock=None)
        ]

        tx1 = self.manager.wallet.prepare_transaction_compute_inputs(
            Transaction, outputs, self.manager.tx_storage)
        tx1.weight = 10
        tx1.parents = self.manager.get_new_tx_parents()
        tx1.timestamp = int(self.clock.seconds())
        tx1.resolve()

        # Change of parents only, so it's a twin
        tx2 = Transaction.create_from_struct(tx1.get_struct())
        tx2.parents = [tx1.parents[1], tx1.parents[0]]
        tx2.resolve()
        self.assertNotEqual(tx1.hash, tx2.hash)

        self.manager.propagate_tx(tx1)
        self.run_to_completion()

        wallet_data = self.manager.tx_storage.wallet_index.get_from_address(
            address)
        self.assertEqual(len(wallet_data), 1)
        self.assertEqual(wallet_data, [tx1.hash])

        # Propagate a conflicting twin transaction
        self.manager.propagate_tx(tx2)
        self.run_to_completion()

        wallet_data = self.manager.tx_storage.wallet_index.get_from_address(
            address)
        self.assertEqual(len(wallet_data), 2)
        self.assertEqual(set(wallet_data), set([tx1.hash, tx2.hash]))
Beispiel #18
0
    def test_tx_methods(self):
        blocks = add_new_blocks(self.manager, 2, advance_clock=1)
        add_blocks_unlock_reward(self.manager)
        txs = add_new_transactions(self.manager, 2, advance_clock=1)

        # Validate __str__, __bytes__, __eq__
        tx = txs[0]
        tx2 = txs[1]
        str_tx = str(tx)
        self.assertTrue(isinstance(str_tx, str))
        self.assertEqual(bytes(tx), tx.get_struct())

        tx_equal = Transaction.create_from_struct(tx.get_struct())
        self.assertTrue(tx == tx_equal)
        self.assertFalse(tx == tx2)

        tx2_hash = tx2.hash
        tx2.hash = None
        self.assertFalse(tx == tx2)
        tx2.hash = tx2_hash

        # Validate is_genesis without storage
        tx_equal.storage = None
        self.assertFalse(tx_equal.is_genesis)

        # Pow error
        tx2.verify_pow()
        tx2.weight = 100
        with self.assertRaises(PowError):
            tx2.verify_pow()

        # Get sighashall is different with and without data
        self.assertNotEqual(tx.get_sighash_all(), tx.get_sighash_all(clear_input_data=False))

        # Verify parent timestamps
        tx2.verify_parents()
        tx2_timestamp = tx2.timestamp
        tx2.timestamp = 2
        with self.assertRaises(TimestampError):
            tx2.verify_parents()
        tx2.timestamp = tx2_timestamp

        # Verify inputs timestamps
        tx2.verify_inputs()
        tx2.timestamp = 2
        with self.assertRaises(TimestampError):
            tx2.verify_inputs()
        tx2.timestamp = tx2_timestamp

        # Validate maximum distance between blocks
        block = blocks[0]
        block2 = blocks[1]
        block2.timestamp = block.timestamp + settings.MAX_DISTANCE_BETWEEN_BLOCKS
        block2.verify_parents()
        block2.timestamp += 1
        with self.assertRaises(TimestampError):
            block2.verify_parents()
    def _test_daa_weight_decay_blocks(self):
        _set_test_mode(TestMode.DISABLED)
        manager = self.create_peer('testnet', tx_storage=self.tx_storage)
        amount = settings.WEIGHT_DECAY_AMOUNT

        from hathor import daa
        daa.AVG_TIME_BETWEEN_BLOCKS = settings.AVG_TIME_BETWEEN_BLOCKS
        daa.MIN_BLOCK_WEIGHT = 2 + 2 * settings.WEIGHT_DECAY_AMOUNT
        add_new_blocks(manager,
                       2 * settings.BLOCK_DIFFICULTY_N_BLOCKS,
                       advance_clock=settings.AVG_TIME_BETWEEN_BLOCKS)

        daa.MIN_BLOCK_WEIGHT = 1
        base_weight = manager.generate_mining_block().weight
        self.assertGreater(base_weight, daa.MIN_BLOCK_WEIGHT)

        add_new_blocks(manager,
                       20,
                       advance_clock=settings.AVG_TIME_BETWEEN_BLOCKS)

        dt = settings.AVG_TIME_BETWEEN_BLOCKS  # the latest call to add_new_blocks will advance the clock
        while dt < settings.WEIGHT_DECAY_ACTIVATE_DISTANCE:
            weight = manager.generate_mining_block().weight
            self.assertAlmostEqual(weight, base_weight)
            manager.reactor.advance(1)
            dt += 1

        dt = 0
        while dt < settings.WEIGHT_DECAY_WINDOW_SIZE:
            weight = manager.generate_mining_block().weight
            self.assertAlmostEqual(weight, base_weight - amount)
            manager.reactor.advance(1)
            dt += 1

        dt = 0
        while dt < settings.WEIGHT_DECAY_WINDOW_SIZE:
            weight = manager.generate_mining_block().weight
            self.assertAlmostEqual(weight, base_weight - 2 * amount)
            manager.reactor.advance(1)
            dt += 1

        manager.reactor.advance(1)
        weight = manager.generate_mining_block().weight
        self.assertAlmostEqual(weight, daa.MIN_BLOCK_WEIGHT)
    def test_daa_weight_decay_blocks(self):
        manager = self.create_peer('testnet', tx_storage=self.tx_storage)
        manager.test_mode = 0
        amount = settings.WEIGHT_DECAY_AMOUNT

        manager.avg_time_between_blocks = settings.AVG_TIME_BETWEEN_BLOCKS
        manager.min_block_weight = 2 + 2 * settings.WEIGHT_DECAY_AMOUNT
        add_new_blocks(manager,
                       2 * settings.BLOCK_DIFFICULTY_N_BLOCKS,
                       advance_clock=settings.AVG_TIME_BETWEEN_BLOCKS)
        manager.min_block_weight = 1

        base_weight = manager.generate_mining_block().weight
        self.assertGreater(base_weight, manager.min_block_weight)

        add_new_blocks(manager,
                       20,
                       advance_clock=settings.AVG_TIME_BETWEEN_BLOCKS)

        dt = settings.AVG_TIME_BETWEEN_BLOCKS  # the latest call to add_new_blocks will advance the clock
        while dt < settings.WEIGHT_DECAY_ACTIVATE_DISTANCE:
            weight = manager.generate_mining_block().weight
            self.assertAlmostEqual(weight, base_weight)
            manager.reactor.advance(1)
            dt += 1

        dt = 0
        while dt < settings.WEIGHT_DECAY_WINDOW_SIZE:
            weight = manager.generate_mining_block().weight
            self.assertAlmostEqual(weight, base_weight - amount)
            manager.reactor.advance(1)
            dt += 1

        dt = 0
        while dt < settings.WEIGHT_DECAY_WINDOW_SIZE:
            weight = manager.generate_mining_block().weight
            self.assertAlmostEqual(weight, base_weight - 2 * amount)
            manager.reactor.advance(1)
            dt += 1

        manager.reactor.advance(1)
        weight = manager.generate_mining_block().weight
        self.assertAlmostEqual(weight, manager.min_block_weight)
    def setUp(self):
        super().setUp()
        self.resource = self.create_resource()
        self.web = StubSite(self.resource)

        # Unlocking wallet
        self.manager.wallet.unlock(b'MYPASS')

        # Creating blocks, txs and a conflict tx to test graphviz with it
        add_new_blocks(self.manager, 2, advance_clock=2)
        add_blocks_unlock_reward(self.manager)
        txs = add_new_transactions(self.manager, 2, advance_clock=2)
        tx = txs[0]

        self.tx2 = Transaction.create_from_struct(tx.get_struct())
        self.tx2.parents = [tx.parents[1], tx.parents[0]]
        self.tx2.resolve()

        self.manager.propagate_tx(self.tx2)
Beispiel #22
0
 def test_validation(self):
     # add 100 blocks and check that walking through get_next_block_best_chain yields the same blocks
     blocks = add_new_blocks(self.manager, 100, advance_clock=1)
     iblocks = iter(blocks)
     block_from_chain = self.last_block
     for _ in range(100):
         block_from_list = next(iblocks)
         block_from_chain = block_from_chain.get_next_block_best_chain()
         self.assertEqual(block_from_chain, block_from_list)
         self.assertTrue(block_from_chain.has_basic_block_parent())
     self.assertEqual(block_from_chain.get_next_block_best_chain(), None)
    def test_tx_weight(self):
        _set_test_mode(TestMode.DISABLED)
        add_new_blocks(self.manager, 3, advance_clock=1)
        add_blocks_unlock_reward(self.manager)
        self.reactor.advance(3)

        # Unlocking wallet
        self.manager.wallet.unlock(b"MYPASS")

        data_json = {
            "outputs": [{
                "address": self.get_address(0),
                "value": 505
            }],
            "inputs": [],
            "weight": 1
        }
        response = yield self.web.post("wallet/send_tokens", {'data': data_json})
        data = response.json_value()
        self.assertFalse(data['success'])
Beispiel #24
0
    def test_get_many(self):
        response1 = yield self.web.get("getmininginfo")
        data1 = response1.json_value()
        self.assertTrue(data1['success'])
        # No blocks
        self.assertEqual(data1['blocks'], 0)
        # Difficulty is 1
        self.assertEqual(data1['difficulty'], 1)

        # Add 10 blocks
        add_new_blocks(self.manager, 10, advance_clock=1)

        response2 = yield self.web.get("getmininginfo")
        data2 = response2.json_value()
        self.assertTrue(data2['success'])
        # 10 blocks
        self.assertEqual(data2['blocks'], 10)
        # Difficulty is 1
        self.assertEqual(data2['difficulty'], 1)
        # Hashrate < 1 because of low weight and many blocks added fast
        self.assertLess(data2['hashrate'], 1)
    def test_block_height(self):
        genesis_block = self.genesis_blocks[0]
        self.assertEqual(genesis_block.get_metadata().height, 0)

        manager = self.create_peer('testnet', tx_storage=self.tx_storage)

        # Mine 50 blocks in a row with no transaction but the genesis
        blocks = add_new_blocks(manager, 50, advance_clock=15)

        for i, block in enumerate(blocks):
            expected_height = i + 1
            self.assertEqual(block.get_metadata().height, expected_height)
Beispiel #26
0
 def setUp(self):
     super().setUp()
     self.web = StubSite(CreateTxResource(self.manager))
     self.manager.wallet.unlock(b'MYPASS')
     self.spent_blocks = add_new_blocks(self.manager, 10)
     self.unspent_blocks = add_blocks_unlock_reward(self.manager)
     add_blocks_unlock_reward(self.manager)
     self.unspent_address = self.manager.wallet.get_unused_address()
     self.unspent_tx = add_new_tx(self.manager, self.unspent_address, 100)
     self.unspent_tx2 = add_new_tx(self.manager, self.unspent_address, 200)
     self.unspent_tx3 = add_new_tx(self.manager, self.unspent_address, 300)
     add_blocks_unlock_reward(self.manager)
    def test_get_data(self):
        genesis_tx = next(x for x in self.manager.tx_storage.get_all_genesis()
                          if x.is_transaction)
        response_success = yield self.web.get(
            "transaction_acc_weight",
            {b'id': bytes(genesis_tx.hash.hex(), 'utf-8')})
        data_success = response_success.json_value()
        self.assertTrue(data_success['success'])
        self.assertEqual(data_success['accumulated_weight'], genesis_tx.weight)
        self.assertEqual(data_success['confirmation_level'], 0)

        # Adding blocks to have funds
        add_new_blocks(self.manager, 2, advance_clock=1)
        add_blocks_unlock_reward(self.manager)
        tx = add_new_transactions(self.manager, 5)[0]
        add_new_blocks(self.manager, 2, advance_clock=1)
        add_blocks_unlock_reward(self.manager)
        response_success2 = yield self.web.get(
            "transaction_acc_weight", {b'id': bytes(tx.hash.hex(), 'utf-8')})
        data_success2 = response_success2.json_value()
        self.assertGreater(data_success2['accumulated_weight'], tx.weight)
        self.assertEqual(data_success2['confirmation_level'], 1)

        # Test sending hash that does not exist
        response_error1 = yield self.web.get(
            "transaction_acc_weight", {
                b'id':
                b'000000831cff82fa730cbdf8640fae6c130aab1681336e2f8574e314a5533848'
            })
        data_error1 = response_error1.json_value()
        self.assertFalse(data_error1['success'])

        # Test sending invalid hash
        response_error2 = yield self.web.get(
            "transaction_acc_weight", {
                b'id':
                b'000000831cff82fa730cbdf8640fae6c130aab1681336e2f8574e314a553384'
            })
        data_error2 = response_error2.json_value()
        self.assertFalse(data_error2['success'])
Beispiel #28
0
    def test_choose_inputs(self):
        blocks = add_new_blocks(self.manager, 1, advance_clock=15)
        blocks_tokens = [
            sum(txout.value for txout in blk.outputs) for blk in blocks
        ]
        add_blocks_unlock_reward(self.manager)

        address = self.manager.wallet.get_unused_address(mark_as_used=False)

        outputs = [
            WalletOutputInfo(address=decode_address(address),
                             value=blocks_tokens[0],
                             timelock=int(self.clock.seconds()) + 10)
        ]

        tx1 = self.manager.wallet.prepare_transaction_compute_inputs(
            Transaction, outputs, self.manager.tx_storage)
        tx1.weight = 10
        tx1.parents = self.manager.get_new_tx_parents()
        tx1.timestamp = int(self.clock.seconds())
        tx1.resolve()
        self.manager.propagate_tx(tx1)
        self.clock.advance(1)

        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(blocks_tokens[0], 0))

        outputs = [
            WalletOutputInfo(address=decode_address(address),
                             value=blocks_tokens[0],
                             timelock=None)
        ]

        with self.assertRaises(InsufficientFunds):
            self.manager.wallet.prepare_transaction_compute_inputs(
                Transaction, outputs, self.manager.tx_storage)

        self.clock.advance(10)

        tx2 = self.manager.wallet.prepare_transaction_compute_inputs(
            Transaction, outputs, self.manager.tx_storage)
        tx2.weight = 10
        tx2.parents = self.manager.get_new_tx_parents()
        tx2.timestamp = int(self.clock.seconds())
        tx2.resolve()
        self.manager.propagate_tx(tx2)

        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(0, blocks_tokens[0]))
    def test_get_tips_histogram(self):
        # Add blocks to have funds
        add_new_blocks(self.manager, 2, 2)
        add_blocks_unlock_reward(self.manager)

        txs = add_new_transactions(self.manager, 10, 2)

        response1 = yield self.web.get(
            "tips-histogram", {
                b'begin': str(txs[0].timestamp).encode(),
                b'end': str(txs[0].timestamp).encode()
            })
        data1 = response1.json_value()
        self.assertTrue(data1['success'])
        self.assertEqual(len(data1['tips']), 1)
        self.assertEqual([txs[0].timestamp, 1], data1['tips'][0])

        response2 = yield self.web.get(
            "tips-histogram", {
                b'begin': str(txs[0].timestamp).encode(),
                b'end': str(txs[0].timestamp + 1).encode()
            })
        data2 = response2.json_value()
        self.assertTrue(data2['success'])
        self.assertEqual(len(data2['tips']), 2)
        self.assertEqual([txs[0].timestamp, 1], data2['tips'][0])
        self.assertEqual([txs[0].timestamp + 1, 1], data2['tips'][1])

        response3 = yield self.web.get(
            "tips-histogram", {
                b'begin': str(txs[0].timestamp).encode(),
                b'end': str(txs[-1].timestamp).encode()
            })
        data3 = response3.json_value()
        self.assertTrue(data3['success'])
        self.assertEqual(len(data3['tips']), 19)
    def test_topological_sort(self):
        _set_test_mode(TestMode.TEST_ALL_WEIGHT)
        _total = 0
        blocks = add_new_blocks(self.manager, 1, advance_clock=1)
        _total += len(blocks)
        blocks = add_blocks_unlock_reward(self.manager)
        _total += len(blocks)
        add_new_transactions(self.manager, 1, advance_clock=1)

        total = 0
        for tx in self.tx_storage._topological_sort():
            total += 1

        # added blocks + genesis txs + added tx
        self.assertEqual(total, _total + 3 + 1)