def test_two_conflicts_intertwined_once(self):
        manager1 = self.create_peer()
        manager1.allow_mining_without_peers()

        miner1 = self.simulator.create_miner(manager1, hashpower=10e6)
        miner1.start()
        self.simulator.run(60)

        gen_tx1 = self.simulator.create_tx_generator(manager1,
                                                     rate=3 / 60.,
                                                     hashpower=1e6,
                                                     ignore_no_funds=True)
        gen_tx1.start()
        self.simulator.run(300)
        gen_tx1.stop()

        # Our full node wallet has a callLater that checks for new utxos every 10 seconds.
        # If we don't run 10 seconds, the utxos generated on the create_tx_generator won't be available,
        # then we might get an insufficient fund error to create the next tx
        self.simulator.run(10)

        self.graphviz = GraphvizVisualizer(manager1.tx_storage,
                                           include_verifications=True,
                                           include_funds=True)

        address = manager1.wallet.get_unused_address(mark_as_used=False)
        value = 10
        initial = gen_new_tx(manager1, address, value)
        initial.weight = 25
        initial.update_hash()
        manager1.propagate_tx(initial, fails_silently=False)
        self.graphviz.labels[initial.hash] = 'initial'

        x = initial
        x = self.do_step(0, manager1, x)
Exemple #2
0
    def new_tx_step1(self):
        """ Generate a new transaction and schedule the mining part of the transaction.
        """
        balance = self.manager.wallet.balance[settings.HATHOR_TOKEN_UID]
        if balance.available == 0 and self.ignore_no_funds:
            self.delayedcall = self.clock.callLater(
                0, self.schedule_next_transaction)
            return

        if not self.send_to:
            address = self.manager.wallet.get_unused_address(
                mark_as_used=False)
        else:
            address = self.rng.choice(self.send_to)

        value = self.rng.randint(1, balance.available)
        self.log.debug('randomized step: send to',
                       address=address,
                       amount=value / 100)

        if not self.double_spending_only:
            try:
                tx = gen_new_tx(self.manager, address, value)
            except (InsufficientFunds, RewardLocked):
                self.delayedcall = self.clock.callLater(
                    0, self.schedule_next_transaction)
                return
        else:
            try:
                tx = gen_new_double_spending(self.manager)
                tx.nonce = self.rng.getrandbits(32)
            except NoCandidatesError:
                self.delayedcall = self.clock.callLater(
                    0, self.schedule_next_transaction)
                return

        tx.weight = daa.minimum_tx_weight(tx)
        tx.update_hash()

        geometric_p = 2**(-tx.weight)
        trials = self.rng.geometric(geometric_p)
        dt = 1.0 * trials / self.hashpower

        self.tx = tx
        self.delayedcall = self.clock.callLater(dt,
                                                self.schedule_next_transaction)
        self.log.debug('randomized step: schedule next transaction',
                       dt=dt,
                       hash=tx.hash_hex)
    def test_soft_voided(self):
        txA_hash = bytes.fromhex(
            '4586c5428e8d666ea59684c1cd9286d2b9d9e89b4939207db47412eeaabc48b2')
        soft_voided_tx_ids = set([
            txA_hash,
        ])

        manager1 = self.create_peer(soft_voided_tx_ids=soft_voided_tx_ids)
        manager1.allow_mining_without_peers()

        miner1 = self.simulator.create_miner(manager1, hashpower=5e6)
        miner1.start()
        self.simulator.run(60)

        gen_tx1 = self.simulator.create_tx_generator(manager1,
                                                     rate=3 / 60.,
                                                     hashpower=1e6,
                                                     ignore_no_funds=True)
        gen_tx1.start()
        self.simulator.run(300)

        manager2 = self.create_peer(soft_voided_tx_ids=soft_voided_tx_ids)
        manager2.soft_voided_tx_ids = soft_voided_tx_ids

        conn12 = FakeConnection(manager1, manager2, latency=0.001)
        self.simulator.add_connection(conn12)

        miner2 = self.simulator.create_miner(manager2, hashpower=10e6)
        miner2.start()

        gen_tx2 = self.simulator.create_tx_generator(manager2,
                                                     rate=10 / 60.,
                                                     hashpower=1e6,
                                                     ignore_no_funds=True)
        gen_tx2.start()
        self.simulator.run(900)
        miner2.stop()
        gen_tx2.stop()

        txA = manager2.tx_storage.get_transaction(txA_hash)
        metaA = txA.get_metadata()
        self.assertEqual({settings.SOFT_VOIDED_ID, txA.hash}, metaA.voided_by)

        txB = add_custom_tx(manager2, [(txA, 0)])
        metaB = txB.get_metadata()
        self.assertEqual({txA.hash}, metaB.voided_by)

        txD1 = add_custom_tx(manager2, [(txB, 0)])
        metaD1 = txD1.get_metadata()
        self.assertEqual({txA.hash}, metaD1.voided_by)

        blk1 = manager2.generate_mining_block()
        self.assertNoParentsAreSoftVoided(blk1)
        if txD1.hash not in blk1.parents:
            blk1.parents[1] = txD1.hash
        blk1.timestamp = txD1.timestamp + 1
        blk1.nonce = self.rng.getrandbits(32)
        blk1.update_hash()
        self.assertTrue(manager2.propagate_tx(blk1, fails_silently=False))
        blk1meta = blk1.get_metadata()
        self.assertIsNone(blk1meta.voided_by)

        self.simulator.run(10)
        address = manager2.wallet.get_unused_address(mark_as_used=True)
        txC = gen_new_tx(manager2, address, 6400)
        if txD1.hash not in txC.parents:
            txC.parents[1] = txD1.hash
        txC.weight = 25
        txC.update_hash()
        manager2.propagate_tx(txC, fails_silently=False)
        metaC = txC.get_metadata()
        self.assertIsNone(metaC.voided_by)

        txD2 = gen_custom_tx(manager2, [(txB, 0)])
        txD2.timestamp = txD1.timestamp + 2
        txD2.update_hash()
        manager2.propagate_tx(txD2, fails_silently=False)

        blk1meta = blk1.get_metadata()
        self.assertIsNone(blk1meta.voided_by)
        metaC = txC.get_metadata()
        self.assertIsNone(metaC.voided_by)
    def test_soft_voided(self):
        soft_voided_tx_ids = set([
            bytes.fromhex(
                '30d49cf336ceb8528a918bed25b729febd3ebc3a8449d5e840aac865d0ca407f'
            ),
            bytes.fromhex(
                '875ef2cdf7405f82f20e0ba115cd2fe07d8c60c50f763f7c48e8d673f56ff4e4'
            ),
            bytes.fromhex(
                'ef0b5e356b82253c8b0f7f078396bd435605dc297b38af3d9623b88ffab43b41'
            ),
            bytes.fromhex(
                'aba55041658213b0bfda880045e5a321cb3d0a88cffa2833e620a2ed1ba27451'
            ),
            bytes.fromhex(
                '43f1782cc7d5702378d067daefea0460cd1976e5479e17accb6f412be8d26ff5'
            ),
            bytes.fromhex(
                '24fe23d0128c85bc149963ff904aefe1c11b44b0e0cddad344b308b34d1dbac8'
            ),
            bytes.fromhex(
                'a6b7b21e4020a70d77fd7467184c65bfb2e4443a0b465b6ace05c1b11b82355b'
            ),
            bytes.fromhex(
                '982e9a2a3f0b1d22eead5ca8cf9a86a5d9edd981ac06f977245a2e664a752e5f'
            ),
            bytes.fromhex(
                'b6cddd95fe02c035fde820add901545662c7b3ae85010cde5914b86cb0a6505e'
            ),
            bytes.fromhex(
                '3a84cff789d3263fea4da636da5c54cb0981a4a0caec1579037a4fa06457f8f3'
            ),
        ])
        manager1 = self.create_peer(soft_voided_tx_ids=soft_voided_tx_ids)
        manager1.allow_mining_without_peers()

        miner1 = self.simulator.create_miner(manager1, hashpower=10e6)
        miner1.start()
        self.simulator.run(60)

        gen_tx1 = self.simulator.create_tx_generator(manager1,
                                                     rate=3 / 60.,
                                                     hashpower=1e6,
                                                     ignore_no_funds=True)
        gen_tx1.start()
        self.simulator.run(300)

        self.graphviz = GraphvizVisualizer(manager1.tx_storage,
                                           include_verifications=True,
                                           include_funds=True)

        address = manager1.wallet.get_unused_address(mark_as_used=False)
        value = 10
        initial = gen_new_tx(manager1, address, value)
        initial.weight = 25
        initial.update_hash()
        manager1.propagate_tx(initial, fails_silently=False)
        self.graphviz.labels[initial.hash] = 'initial'

        x = initial
        b0 = self.gen_block(manager1, x)
        self.graphviz.labels[b0.hash] = 'b0'

        x = self.do_step(0, manager1, x)
        b1 = self.gen_block(manager1, x, parent_block=b0)
        self.graphviz.labels[b1.hash] = 'b1'

        x = self.do_step(1, manager1, x)
        b2 = self.gen_block(manager1, x, parent_block=b1)
        self.graphviz.labels[b2.hash] = 'b2'

        x = self.do_step(2, manager1, x)
        b3 = self.gen_block(manager1, x, parent_block=b2)
        self.graphviz.labels[b3.hash] = 'b3'

        x = self.do_step(3, manager1, x)
        b4 = self.gen_block(manager1, x, parent_block=b3)
        self.graphviz.labels[b4.hash] = 'b4'

        x = self.do_step(4, manager1, x)
        b5 = self.gen_block(manager1, x, parent_block=b4)
        self.graphviz.labels[b5.hash] = 'b5'

        self.assertIsNone(b0.get_metadata().voided_by)
        self.assertIsNone(b1.get_metadata().voided_by)
        self.assertIsNone(b2.get_metadata().voided_by)
        self.assertIsNone(b3.get_metadata().voided_by)
        self.assertIsNone(b4.get_metadata().voided_by)
        self.assertIsNone(b5.get_metadata().voided_by)

        for tx in manager1.tx_storage.get_all_transactions():
            meta = tx.get_metadata()
            voided_by = meta.voided_by or set()
            if settings.SOFT_VOIDED_ID in voided_by:
                self.assertTrue({settings.SOFT_VOIDED_ID,
                                 tx.hash}.issubset(voided_by))

        txF1 = self.txF1_0
        txF2 = self.txF2_0

        txB = self.txB_0
        txB_meta = txB.get_metadata()
        txB_spent_list = txB_meta.spent_outputs[0]
        self.assertEqual(set(txB_spent_list), {txF1.hash, txF2.hash})
        self.assertIsNone(txB_meta.get_output_spent_by(0))

        txD1 = self.txD1_0
        txD1_meta = txD1.get_metadata()
        txD1_spent_list = txD1_meta.spent_outputs[0]
        self.assertEqual([txF2.hash], txD1_spent_list)
        self.assertIsNone(txD1_meta.get_output_spent_by(0))
    def test_soft_voided(self):
        txA_hash = bytes.fromhex(
            '4586c5428e8d666ea59684c1cd9286d2b9d9e89b4939207db47412eeaabc48b2')
        soft_voided_tx_ids = set([
            txA_hash,
        ])

        manager1 = self.create_peer(soft_voided_tx_ids=soft_voided_tx_ids)
        manager1.allow_mining_without_peers()

        miner1 = self.simulator.create_miner(manager1, hashpower=5e6)
        miner1.start()
        self.simulator.run(60)

        gen_tx1 = self.simulator.create_tx_generator(manager1,
                                                     rate=3 / 60.,
                                                     hashpower=1e6,
                                                     ignore_no_funds=True)
        gen_tx1.start()
        self.simulator.run(300)

        manager2 = self.create_peer(soft_voided_tx_ids=soft_voided_tx_ids)
        manager2.soft_voided_tx_ids = soft_voided_tx_ids

        graphviz = GraphvizVisualizer(manager2.tx_storage,
                                      include_verifications=True,
                                      include_funds=True)

        conn12 = FakeConnection(manager1, manager2, latency=0.001)
        self.simulator.add_connection(conn12)

        miner2 = self.simulator.create_miner(manager2, hashpower=10e6)
        miner2.start()
        gen_tx2 = self.simulator.create_tx_generator(manager2,
                                                     rate=10 / 60.,
                                                     hashpower=1e6,
                                                     ignore_no_funds=True)
        gen_tx2.start()
        self.simulator.run(900)

        txA = manager2.tx_storage.get_transaction(txA_hash)
        metaA = txA.get_metadata()
        self.assertEqual({settings.SOFT_VOIDED_ID, txA.hash}, metaA.voided_by)
        graphviz.labels[txA.hash] = 'txA'

        txB = add_custom_tx(manager2, [(txA, 0)])
        metaB = txB.get_metadata()
        self.assertEqual({txA.hash}, metaB.voided_by)
        graphviz.labels[txB.hash] = 'txB'

        txD1 = add_custom_tx(manager2, [(txB, 0)])
        metaD1 = txD1.get_metadata()
        self.assertEqual({txA.hash}, metaD1.voided_by)
        graphviz.labels[txD1.hash] = 'txD1'

        txD2 = add_custom_tx(manager2, [(txB, 0)])
        metaD2 = txD2.get_metadata()
        self.assertEqual({txA.hash, txD2.hash}, metaD2.voided_by)
        graphviz.labels[txD2.hash] = 'txD2'
        metaD1 = txD1.get_metadata()
        self.assertEqual({txA.hash, txD1.hash}, metaD1.voided_by)

        address = manager2.wallet.get_unused_address(mark_as_used=False)
        value = 1
        txC = gen_new_tx(manager2, address, value)
        txC.parents[0] = txA.hash
        txC.timestamp = max(txC.timestamp, txA.timestamp + 1)
        txC.weight = 25
        txC.update_hash()
        self.assertTrue(manager2.propagate_tx(txC, fails_silently=False))
        metaC = txC.get_metadata()
        self.assertIsNone(metaC.voided_by)
        graphviz.labels[txC.hash] = 'txC'

        blk1 = manager2.generate_mining_block()
        self.assertNoParentsAreSoftVoided(blk1)
        blk1.parents[1] = txA.hash
        blk1.nonce = self.rng.getrandbits(32)
        blk1.update_hash()
        self.assertTrue(manager2.propagate_tx(blk1, fails_silently=False))
        blk1meta = blk1.get_metadata()
        self.assertIsNone(blk1meta.voided_by)
        graphviz.labels[blk1.hash] = 'b1'

        blk2 = manager2.generate_mining_block()
        self.assertNoParentsAreSoftVoided(blk2)
        if txD1.hash not in blk2.parents:
            blk2.parents[1] = txD1.hash
        blk2.nonce = self.rng.getrandbits(32)
        blk2.update_hash()
        self.assertTrue(manager2.propagate_tx(blk2, fails_silently=False))
        blk2meta = blk2.get_metadata()
        self.assertIsNone(blk2meta.voided_by)
        graphviz.labels[blk2.hash] = 'b2'

        blk3 = manager2.generate_mining_block()
        self.assertNoParentsAreSoftVoided(blk3)
        blk3.parents[1] = txD2.hash
        blk3.nonce = self.rng.getrandbits(32)
        blk3.update_hash()
        self.assertTrue(manager2.propagate_tx(blk3, fails_silently=False))
        blk3meta = blk3.get_metadata()
        self.assertIsNone(blk3meta.voided_by)
        graphviz.labels[blk3.hash] = 'b3'

        for tx in manager1.tx_storage.get_all_transactions():
            meta = tx.get_metadata()
            voided_by = meta.voided_by or set()
            if settings.SOFT_VOIDED_ID in voided_by:
                self.assertTrue({settings.SOFT_VOIDED_ID,
                                 tx.hash}.issubset(voided_by))