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