class cleanup_solutionsTestCase(TestCase): def setUp(self): self.miner = Miner() self.miner.save() self.worker = Worker(miner=self.miner) self.worker.save() def test_cleanup(self): older = timezone.now() - datetime.timedelta( days=settings.POOL_CLEANUP_MAXDAYS + 8) # an older entry work = Work(worker=self.worker, ip="1.1.1.1") work.save() work.inserted_at = older work.save() # and a new work entry work2 = Work(worker=self.worker, ip="2.2.2.2") work2.save() self.assertEqual(len(Work.objects.all()), 2) cleanup_solutions() self.assertEqual(len(Work.objects.all()), 1) self.assertEqual(Work.objects.all()[0].ip, '2.2.2.2')
def setUp(self): self.miner = Miner() self.miner.save() self.worker = Worker(miner=self.miner) self.worker.save() self.work = Work( hash_target= "0000000111100000000000000000000000000000000000000000000000000000", worker=self.worker, ip="1.1.1.1") self.work.save() self.solution_string = SolutionString() self.solution_string.content = { 'transaction_hex': 'TransHex', 'thread_hash_counter': '332694', 'prev_block_time': '1518041437', 'prev_height': '19309', 'nonce': '14217', 'block_hash': 'ABCD', 'miner_id': self.miner.id, 'work_id': self.work.id, 'block_time': '1518041523', 'thread_id': '0', 'timer_start': '1518037739857', 'thread_start': '1518040817888', 'bible_hash': '0000000e5bced1fccc7110dfd386cf461b82852ce4eec5e124ca8f5e5bcc5a11', 'hash_counter': '1769512', 'timer_end': '1518041527556', 'block_hex': 'BlockHex' } self.solution_s = self.solution_string.as_string()
def setUp(self): self.miner = Miner() self.miner.save() self.solution_string = SolutionString() self.solution_string.content = { 'miner_id': self.miner.id, }
def setUp(self): self.miner = Miner(network="test", address="B91RjV9UoZa5qLNbWZFXJ42sFWbJCyxxxx") self.miner.save() self.block_time = datetime.datetime(2017, 9, 9, 11, 12, 13, 15, tzinfo=datetime.timezone.utc)
class MinerCalculationTestCase(TestCase): def setUp(self): self.miner1 = Miner(network="test", address="B91RjV9UoZa5qLNbWZFXJ42sFWbJCyxxxx") self.miner1.save() self.miner2 = Miner(network="test", address="B91RjV9UoZa5qLNbWZFXJ42sFWbJCyxxx2") self.miner2.save() Transaction(miner=self.miner1, network="test", amount=10).save() Transaction(miner=self.miner1, network="test", amount=5).save() Transaction(miner=self.miner1, network="test", amount=-2).save() # should not happen, but better safe then sorry Transaction(miner=self.miner1, network="main", amount=100).save() Transaction(miner=self.miner2, network="test", amount=99).save() Transaction(miner=self.miner2, network="test", amount=-90).save() def test_basic(self): self.miner1.update_balance() self.miner2.update_balance() self.assertEqual(self.miner1.balance, 13) self.assertEqual(self.miner2.balance, 9)
def setUp(self): # the miner 1 starts with a fake balance self.miner1 = Miner(network="test", balance=20, address="B91RjV9UoZa5qLNbWZFXJ42sFWbJCyxxxx") self.miner1.save() # as the user above, but with not enough balance self.miner2 = Miner(network="test", balance=1, address="B91RjV9UoZa5qLNbWZFXJ42sFWbJCyxxx2") self.miner2.save() Transaction(miner=self.miner1, amount=4, network="test").save() Transaction(miner=self.miner2, amount=1, network="test").save()
def handle(self, *args, **options): super(Command, self).handle(*args, **options) miner = Miner.objects.get(pk=options['miner_id']) value = Miner.calculate_miner_balance(miner.network, miner.id) miner.balance = value miner.save()
def setUp(self): self.miner1 = Miner(network="test", address="B91RjV9UoZa5qLNbWZFXJ42sFWbJCyxxxx") self.miner1.save() self.miner2 = Miner(network="test", address="B91RjV9UoZa5qLNbWZFXJ42sFWbJCyxxx2") self.miner2.save() Transaction(miner=self.miner1, network="test", amount=10).save() Transaction(miner=self.miner1, network="test", amount=5).save() Transaction(miner=self.miner1, network="test", amount=-2).save() # should not happen, but better safe then sorry Transaction(miner=self.miner1, network="main", amount=100).save() Transaction(miner=self.miner2, network="test", amount=99).save() Transaction(miner=self.miner2, network="test", amount=-90).save()
def setUp(self): self.miner = Miner() self.miner.save() self.worker = Worker(miner=self.miner) self.worker.save() self.solution_string = SolutionString() self.solution_string.content = { 'transaction_hex': '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05026e4b0103ffffffff01ca6940057a0100001976a914e83c22b58de63a91952524084f46415c985d715c88acfdce013c5645523e312e302e382e363c2f5645523e3c4d494e4552475549443e65656635636263622d663637332d343230332d613739312d6637373362313737663164663c2f4d494e4552475549443e3c706f6c6d6573736167653e666531313263363532643964643063663436326135333762636466363561323537663461613331303032396666373432383964396366623665303161396662623c2f706f6c6d6573736167653e3c706f6c7765696768743e35363438302e35313c2f706f6c7765696768743e3c706f6c616d6f756e743e31363437342e30303c2f706f6c616d6f756e743e3c706f6c6176676167653e332e3432393c2f706f6c6176676167653e3c5349475f303e494d3736436d344e57376e554e78614e5050797662373473424d437945586e314d49347339376b4f334d475a6469672f496a59486c48594139637346616b3769756451536c6769596f643366756d4c2f44797075706e593d3c2f5349475f303e3c5349475f313e494e684d7a47487658727a4b654366424e384d4c584671466b45495a36455758694a572f6535334e73384e4c5652755274535877395830337937452b46447a7a68455762744756543868307a42477751484c33305930513d3c2f5349475f313e00000000', 'thread_hash_counter': '332694', 'prev_block_time': '1518041437', 'prev_height': '19309', 'nonce': '14217', 'block_hash': '4adfaf0c3ad50afecad53ad1e57340e9735bca7d104b2b3565835a346e1c6c96', 'miner_id': self.miner.id, 'work_id': 'b0181b3a-9868-4139-bef5-8c7e5d4239f4', 'block_time': '1518041523', 'thread_id': '0', 'timer_start': '1518037739857', 'thread_start': '1518040817888', 'bible_hash': '0000000e5bced1fccc7110dfd386cf461b82852ce4eec5e124ca8f5e5bcc5a11', 'hash_counter': '1769512', 'timer_end': '1518041527556', 'block_hex': '000000209928ce1b5ba829fde591237d3876df45daa2dd30ec31805b43dd6b972eae9aff3fab6ced6b34254aeb8c7f004cb82178984dbf22ea5c5316ac33ae6ec90ef17db3797b5aa5aa081d893700000201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05026e4b0103ffffffff01ca6940057a0100001976a914e83c22b58de63a91952524084f46415c985d715c88acfdce013c5645523e312e302e382e363c2f5645523e3c4d494e4552475549443e65656635636263622d663637332d343230332d613739312d6637373362313737663164663c2f4d494e4552475549443e3c706f6c6d6573736167653e666531313263363532643964643063663436326135333762636466363561323537663461613331303032396666373432383964396366623665303161396662623c2f706f6c6d6573736167653e3c706f6c7765696768743e35363438302e35313c2f706f6c7765696768743e3c706f6c616d6f756e743e31363437342e30303c2f706f6c616d6f756e743e3c706f6c6176676167653e332e3432393c2f706f6c6176676167653e3c5349475f303e494d3736436d344e57376e554e78614e5050797662373473424d437945586e314d49347339376b4f334d475a6469672f496a59486c48594139637346616b3769756451536c6769596f643366756d4c2f44797075706e593d3c2f5349475f303e3c5349475f313e494e684d7a47487658727a4b654366424e384d4c584671466b45495a36455758694a572f6535334e73384e4c5652755274535877395830337937452b46447a7a68455762744756543868307a42477751484c33305930513d3c2f5349475f313e00000000010000000223e3f54cbfd562a065218f2f5be70a9d22e6ff7820dd0d1f701a53afb53767170000000049483045022100d612e1ee658823964ebdc3dedcecf2e9c19c7a9891ba264b8ba170cdfed58fbd02201d4de4c922afa8c218aa8fe6b73eadd62f00109cd777b3f7489f50eab83d3da301feffffff3fab86d7035b899793e1264899b1838fd6b988a7adc1866365dbd06250c65f260000000048473044022005004171fbc47a417c5c68e3abfd8a76e375029866b779ae117730d61ff64bab0220268e22a951608a7050747fa9e373d7610b11eb3de663f954affdf394941b777501feffffff0225b74458390000001976a9146ebc0349fad92dbb1b277ea9209609b5a485e4f988ac1f3c706f6c7765696768743e31343031312e30303c2f706f6c7765696768743ed6e9123b46010000232103dbeb934062e53b5deef24a89825b225eeea09c31037693ac7d192c5c581e1fbcac1f3c706f6c7765696768743e31343031312e30303c2f706f6c7765696768743e6d4b0000' }
class WorkerIdTestCase(TestCase): def setUp(self): self.miner = Miner(address='123456', network="main") self.miner.save() self.worker = Worker(miner=self.miner, name="abc") self.worker.save() def test_parsing(self): with self.assertRaises(InvalidWorkerdId) as e: worker_id = WorkerId('') with self.assertRaises(InvalidWorkerdId) as e: worker_id = WorkerId('/') with self.assertRaises(InvalidWorkerdId) as e: worker_id = WorkerId('//') worker_id = WorkerId('123456') self.assertEqual(worker_id.get_address(), "123456") self.assertEqual(worker_id.get_worker(), 'Default') self.assertEqual(worker_id.get_email(), None) worker_id = WorkerId('123456/') self.assertEqual(worker_id.get_address(), "123456") self.assertEqual(worker_id.get_worker(), 'Default') self.assertEqual(worker_id.get_email(), None) worker_id = WorkerId('123456/abc') self.assertEqual(worker_id.get_address(), "123456") self.assertEqual(worker_id.get_worker(), "abc") self.assertEqual(worker_id.get_email(), None) worker_id = WorkerId('123456/abc/[email protected]') self.assertEqual(worker_id.get_address(), "123456") self.assertEqual(worker_id.get_worker(), "abc") self.assertEqual(worker_id.get_email(), "*****@*****.**") self.assertEqual(worker_id.get_worker_obj('main'), self.worker) with self.assertRaises(MinerNotFound) as e: self.assertEqual(worker_id.get_worker_obj('test'), self.worker)
def miner(request, network, address): """ the miner share statistics and transaction list """ miner = get_object_or_404(Miner, address=address, network=network) share_statistics = get_miner_solution_statistics(network, miner_id=miner.id) transactions = Transaction.objects.filter( network=network, miner=miner).order_by('-id')[0:100] workers = Miner.get_active_worker(network, address, 1) error_msgs = miner_error_message_statistic(network, miner_id=miner.id) return render( request, 'purepool/miner.html', { 'address': address, 'network': network, 'miner': miner, 'workers': workers, 'share_statistics': share_statistics, 'transactions': transactions, 'error_msgs': error_msgs, })
def setUp(self): self.miner1 = Miner(network="test", address="B91RjV9UoZa5qLNbWZFXJ42sFWbJCyxxxx") self.miner1.save() self.worker1 = Worker(miner=self.miner1) self.worker1.save() self.miner2 = Miner(network="test", address="B91RjV9UoZa5qLNbWZFXJ42sFWbJCyxxx2") self.miner2.save() self.worker2 = Worker(miner=self.miner2) self.worker2.save() self.insert_age = timezone.now() - datetime.timedelta(days=3) Transaction(miner=self.miner2, amount=60, network="test").save() # test network #---------------- # valid block1 = Block(height=1, network='test', process_status='BP', pool_block=True, subsidy=100) block1.save() # not a pool block block2 = Block(height=2, network='test', pool_block=False, subsidy=1) block2.save() # wrong status block3 = Block(height=3, network='test', process_status='OP', pool_block=True, subsidy=1) block3.save() Block.objects.all().update(inserted_at=self.insert_age) # not old enough block4 = Block(height=4, network='test', process_status='BP', pool_block=True, subsidy=1) block4.save() work_test1 = Work(worker=self.worker1, ip="1.1.1.1") work_test1.save() work_test2 = Work(worker=self.worker1, ip="1.1.1.1") work_test2.save() Solution(network='test', block=block1, bible_hash="1", miner=self.miner1, work=work_test1).save() Solution(network='test', block=block1, bible_hash="2", miner=self.miner1, work=work_test1).save() Solution(network='test', block=block1, bible_hash="3", miner=self.miner1, work=work_test1).save() Solution(network='test', block=block1, bible_hash="4", miner=self.miner2, work=work_test1).save() Solution(network='test', block=block1, bible_hash="4.5", miner=self.miner2, work=work_test1).save() Solution(network='test', block=block2, bible_hash="5", miner=self.miner1, work=work_test1).save() Solution(network='test', block=block3, bible_hash="6", miner=self.miner1, work=work_test1).save() Solution(network='test', block=block4, bible_hash="7", miner=self.miner1, work=work_test1).save() # main network # ----------------- block1 = Block(height=1, network='main', process_status='BP', pool_block=True, subsidy=1) block1.save() Block.objects.filter(network="main").update( inserted_at=self.insert_age) work_main = Work(worker=self.worker1, ip="1.1.1.1") work_main.save() Solution(network='main', block=block2, bible_hash="8", miner=self.miner1, work=work_main).save()
class shareout_next_blockTestCase(TestCase): def setUp(self): self.miner1 = Miner(network="test", address="B91RjV9UoZa5qLNbWZFXJ42sFWbJCyxxxx") self.miner1.save() self.worker1 = Worker(miner=self.miner1) self.worker1.save() self.miner2 = Miner(network="test", address="B91RjV9UoZa5qLNbWZFXJ42sFWbJCyxxx2") self.miner2.save() self.worker2 = Worker(miner=self.miner2) self.worker2.save() self.insert_age = timezone.now() - datetime.timedelta(days=3) Transaction(miner=self.miner2, amount=60, network="test").save() # test network #---------------- # valid block1 = Block(height=1, network='test', process_status='BP', pool_block=True, subsidy=100) block1.save() # not a pool block block2 = Block(height=2, network='test', pool_block=False, subsidy=1) block2.save() # wrong status block3 = Block(height=3, network='test', process_status='OP', pool_block=True, subsidy=1) block3.save() Block.objects.all().update(inserted_at=self.insert_age) # not old enough block4 = Block(height=4, network='test', process_status='BP', pool_block=True, subsidy=1) block4.save() work_test1 = Work(worker=self.worker1, ip="1.1.1.1") work_test1.save() work_test2 = Work(worker=self.worker1, ip="1.1.1.1") work_test2.save() Solution(network='test', block=block1, bible_hash="1", miner=self.miner1, work=work_test1).save() Solution(network='test', block=block1, bible_hash="2", miner=self.miner1, work=work_test1).save() Solution(network='test', block=block1, bible_hash="3", miner=self.miner1, work=work_test1).save() Solution(network='test', block=block1, bible_hash="4", miner=self.miner2, work=work_test1).save() Solution(network='test', block=block1, bible_hash="4.5", miner=self.miner2, work=work_test1).save() Solution(network='test', block=block2, bible_hash="5", miner=self.miner1, work=work_test1).save() Solution(network='test', block=block3, bible_hash="6", miner=self.miner1, work=work_test1).save() Solution(network='test', block=block4, bible_hash="7", miner=self.miner1, work=work_test1).save() # main network # ----------------- block1 = Block(height=1, network='main', process_status='BP', pool_block=True, subsidy=1) block1.save() Block.objects.filter(network="main").update( inserted_at=self.insert_age) work_main = Work(worker=self.worker1, ip="1.1.1.1") work_main.save() Solution(network='main', block=block2, bible_hash="8", miner=self.miner1, work=work_main).save() @override_settings( POOL_ADDRESS={'POOL_BLOCK_MATURE_HOURS': { 'test': 48, 'main': 48 }}) @override_settings(POOL_ADDRESS={'test': 'abc', 'main': 'xyz'}) @override_settings(POOL_FEE_PERCENT=5) @mock.patch('purepool.models.solution.tasks.BiblePayRpcClient.subsidy', return_value={ 'subsidy': '100', 'recipient': 'abc' }) def test_process(self, mock_subsidy): # sucessfull first block shareout_next_block('test') block1 = Block.objects.get(height=1, network="test") self.assertEqual(block1.process_status, 'FI') self.assertEqual(Transaction.objects.all().count(), 3) # 1 old, 2 new self.assertEqual( Solution.objects.filter(block=block1, processed=True).count(), 5) trans1 = Transaction.objects.get(miner=self.miner1) trans2 = Transaction.objects.get(miner=self.miner2, amount=38) self.assertEqual(trans1.amount, 57) self.assertEqual(trans1.network, "test") self.assertEqual(trans1.miner, self.miner1) self.assertEqual(trans1.category, "MS") self.assertEqual(trans2.amount, 38) self.assertEqual(trans2.network, "test") self.assertEqual(trans2.miner, self.miner2) self.assertEqual(trans2.category, "MS") miner1 = Miner.objects.get(pk=self.miner1.id) self.assertEqual(miner1.balance, 57) # miner 2 already had an open transaction, so the balance is higher miner2 = Miner.objects.get(pk=self.miner2.id) self.assertEqual(miner2.balance, 98) # no more blocks, main untouched # all existing blocks not fit our requirements shareout_next_block('test') shareout_next_block('test') shareout_next_block('test') shareout_next_block('test') self.assertEqual(Transaction.objects.all().count(), 3) # old old, 2 new block2 = Block.objects.get(height=2, network="test") self.assertEqual(block2.process_status, 'OP') block3 = Block.objects.get(height=3, network="test") self.assertEqual(block3.process_status, 'OP') block4 = Block.objects.get(height=4, network="test") self.assertEqual(block4.process_status, 'BP') blockmain = Block.objects.get(height=1, network="main") self.assertEqual(blockmain.process_status, 'BP') @override_settings( POOL_ADDRESS={'POOL_BLOCK_MATURE_HOURS': { 'test': 48, 'main': 48 }}) @override_settings(POOL_ADDRESS={'test': 'abc', 'main': 'xyz'}) def test_stale(self): # not our block (anymore)? with mock.patch( 'purepool.models.solution.tasks.BiblePayRpcClient.subsidy', return_value={"XXX": 'xxx'}): # marked as stale shareout_next_block('test') block1 = Block.objects.get(height=1, network="test") self.assertEqual(block1.process_status, 'ST') self.assertEqual(Transaction.objects.all().count(), 1) # one old @override_settings(POOL_BLOCK_MATURE_HOURS={'test': 48, 'main': 48}) @override_settings(POOL_ADDRESS={'test': 'abc', 'main': 'xyz'}) def test_process_noshares(self): # remove all shares and test Solution.objects.all().delete() with mock.patch( 'purepool.models.solution.tasks.BiblePayRpcClient.subsidy', return_value={ 'subsidy': '55', 'recipient': 'abc' }): shareout_next_block('test') block1 = Block.objects.get(height=1, network="test") self.assertEqual(block1.process_status, 'FI') self.assertEqual(Transaction.objects.all().count(), 1) # one old @override_settings( POOL_ADDRESS={'POOL_BLOCK_MATURE_HOURS': { 'test': 48, 'main': 48 }}) @override_settings(POOL_ADDRESS={'test': 'abc', 'main': 'xyz'}) def test_process_nosubsidy(self): # set subsidy to of all blocks Block.objects.all().update(subsidy=0) with mock.patch( 'purepool.models.solution.tasks.BiblePayRpcClient.subsidy', return_value={ 'subsidy': '0', 'recipient': 'abc' }): # should be marked as FI shareout_next_block('test') block1 = Block.objects.get(height=1, network="test") self.assertEqual(block1.process_status, 'FI') self.assertEqual(Transaction.objects.all().count(), 1) # one old
def setUp(self): miner = Miner(address="B91RjV9UoZa5qLNbWZFXJ42sFWbJCyxxxx") miner.save() worker = Worker(miner=miner) worker.save() work_test = Work(worker=worker, ip="1.1.1.1") work_test.save() work_main = Work(worker=worker, ip="1.1.1.1") work_main.save() # first, we add some blocks in both networks, # with only some being pool bocks self.block1_main = Block(height=4, network='main', miner=miner, subsidy=1) self.block1_main.save() self.block2_main = Block(height=4, network='main', pool_block=True, miner=miner, subsidy=1) self.block2_main.save() self.block1_test = Block(height=5, network='test', pool_block=True, miner=miner, subsidy=1) self.block1_test.save() self.block2_test = Block(height=6, network='test', miner=miner, subsidy=1) self.block2_test.save() self.block2_test = Block(height=7, network='test', pool_block=True, miner=miner, subsidy=1) self.block2_test.save() # next we set the inserted_time for two of the blocks # to match the solutions self.block1_test.inserted_at = timezone.now() - datetime.timedelta( days=4) self.block1_test.save() self.block2_test.inserted_at = timezone.now() - datetime.timedelta( days=1) self.block2_test.save() # and now some solutions to attch to the block s1 = Solution(network='test', bible_hash="1", miner=miner, work=work_test) s1.save() s1.inserted_at = timezone.now() - datetime.timedelta(days=5) s1.save() s2 = Solution(network='test', bible_hash="2", miner=miner, work=work_test) s2.save() s2.inserted_at = timezone.now() - datetime.timedelta(days=2) s2.save() s3 = Solution(network='test', bible_hash="3", miner=miner, work=work_test) s3.save() s4 = Solution(network='main', bible_hash="4", miner=miner, work=work_main) s4.save() s4.inserted_at = timezone.now() - datetime.timedelta(days=10) s4.save()
class send_autopaymentsTestCase(TestCase): def setUp(self): # the miner 1 starts with a fake balance self.miner1 = Miner(network="test", balance=20, address="B91RjV9UoZa5qLNbWZFXJ42sFWbJCyxxxx") self.miner1.save() # as the user above, but with not enough balance self.miner2 = Miner(network="test", balance=1, address="B91RjV9UoZa5qLNbWZFXJ42sFWbJCyxxx2") self.miner2.save() Transaction(miner=self.miner1, amount=4, network="test").save() Transaction(miner=self.miner2, amount=1, network="test").save() @override_settings(POOL_MINIMUM_AUTOSEND={'main': 10, 'test': 10}) @mock.patch('puretransaction.tasks.BiblePayRpcClient.sendtoaddress', return_value="TXTEST") @mock.patch('time.sleep', return_value="") def test_wrongvalue(self, mock_sendtoaddress, mock_sleep): # balance in Miner table is higher then the real balance send_autopayments("test") miner1 = Miner.objects.get(pk=self.miner1.id) self.assertEqual(miner1.balance, 4) self.assertEqual(Transaction.objects.filter(category='TX').count(), 0) @override_settings(POOL_MINIMUM_AUTOSEND={'main': 10, 'test': 10}) @mock.patch('puretransaction.tasks.BiblePayRpcClient.sendtoaddress', return_value="TXTEST") @mock.patch('time.sleep', return_value="") def test_outdated_value(self, mock_sendtoaddress, mock_sleep): # balance is high enough, but not right Transaction(miner=self.miner1, amount=10, network="test").save() send_autopayments("test") miner1 = Miner.objects.get(pk=self.miner1.id) self.assertEqual(miner1.balance, 0) self.assertEqual(Transaction.objects.filter(category='TX').count(), 1) tx = Transaction.objects.get(category='TX') self.assertEqual(tx.amount, -14) self.assertEqual(tx.miner.id, miner1.id) self.assertEqual(tx.network, "test") @override_settings(POOL_MINIMUM_AUTOSEND={'main': 10, 'test': 10}) @mock.patch('puretransaction.tasks.BiblePayRpcClient.sendtoaddress', return_value="TXTEST") def test_error_on_send(self, mock_sendtoaddress): mock_sendtoaddress.side_effect = Exception() Transaction(miner=self.miner1, amount=10, network="test").save() send_autopayments("test") @override_settings(POOL_MINIMUM_AUTOSEND={'main': 10, 'test': 10}) @mock.patch('puretransaction.tasks.BiblePayRpcClient.sendtoaddress', return_value="TXTEST") @mock.patch('time.sleep', return_value="") def test_process(self, mock_sendtoaddress, mock_sleep): # a successfull run Transaction(miner=self.miner1, amount=30, network="test").save() self.miner1.update_balance() self.miner1.save() Transaction(miner=self.miner1, amount=10, network="test").save() send_autopayments("test") miner1 = Miner.objects.get(pk=self.miner1.id) self.assertEqual(miner1.balance, 0) self.assertEqual(Transaction.objects.filter(category='TX').count(), 1) tx = Transaction.objects.get(category='TX') self.assertEqual(tx.amount, -44) self.assertEqual(tx.miner.id, miner1.id) self.assertEqual(tx.network, "test") # even with a new balance, should not pay again, as we do not pay so early again Transaction(miner=self.miner1, amount=16, network="test").save() self.miner1.update_balance() self.miner1.save() send_autopayments("test") miner1 = Miner.objects.get(pk=self.miner1.id) self.assertEqual(miner1.balance, 16) self.assertEqual(Transaction.objects.filter(category='TX').count(), 1) tx = Transaction.objects.get(category='TX') self.assertEqual(tx.amount, -44) self.assertEqual(tx.miner.id, miner1.id) self.assertEqual(tx.network, "test") # but if first_trans is older, then the second one should be paid tx.inserted_at = timezone.now() - datetime.timedelta(hours=18) tx.save() send_autopayments("test") miner1 = Miner.objects.get(pk=self.miner1.id) self.assertEqual(miner1.balance, 0) self.assertEqual(Transaction.objects.filter(category='TX').count(), 2) tx = Transaction.objects.filter(category='TX').order_by('-id')[0] self.assertEqual(tx.amount, -16) self.assertEqual(tx.miner.id, miner1.id) self.assertEqual(tx.network, "test") @override_settings(POOL_MINIMUM_AUTOSEND={'main': 10, 'test': 10}) @mock.patch('puretransaction.tasks.BiblePayRpcClient.sendtoaddress', return_value="TXTEST") def test_process_failed(self, mock_sendtoaddress): mock_sendtoaddress.side_effect = Exception() # a successfull run Transaction(miner=self.miner1, amount=30, network="test").save() self.miner1.update_balance() self.miner1.save() Transaction(miner=self.miner1, amount=10, network="test").save() send_autopayments("test") miner1 = Miner.objects.get(pk=self.miner1.id) self.assertEqual(miner1.balance, 34) # transaction wasn't done self.assertEqual(Transaction.objects.filter(category='TX').count(), 0) self.assertEqual(TransactionError.objects.all().count(), 1)
class find_new_blocksTestCase(TestCase): def setUp(self): self.miner = Miner(network="test", address="B91RjV9UoZa5qLNbWZFXJ42sFWbJCyxxxx") self.miner.save() self.block_time = datetime.datetime(2017, 9, 9, 11, 12, 13, 15, tzinfo=datetime.timezone.utc) @override_settings(POOL_ADDRESS={'test': 'POOLADDR'}) def test_basic(self): test_block_time1 = datetime.datetime(2017, 9, 9, 11, 12, 13, 15, tzinfo=datetime.timezone.utc) test_block_time2 = datetime.datetime(2018, 9, 9, 11, 12, 13, 15, tzinfo=datetime.timezone.utc) test_block_time3 = datetime.datetime(2019, 9, 9, 11, 12, 13, 15, tzinfo=datetime.timezone.utc) test_block_time4 = datetime.datetime(2020, 9, 9, 11, 12, 13, 15, tzinfo=datetime.timezone.utc) with mock.patch('purepool.models.block.tasks.BiblePayRpcClient.subsidy') as mock_subsidy, \ mock.patch('purepool.models.block.tasks.get_block_time') as mock_get_block_time: # the mock client will return the result for two block mock_subsidy.side_effect = [{ 'subsidy': 100, 'minerguid': 'unknown', 'recipient': 'POOLADDR' }, { 'subsidy': 500, 'minerguid': self.miner.id, 'recipient': 'POOLADDR' }, { 'subsidy': 200, 'minerguid': 'xxx', 'recipient': 'rec' }, None] mock_get_block_time.side_effect = [ test_block_time1, test_block_time2, test_block_time3, test_block_time4, ] find_new_blocks('test') mock_subsidy.assert_has_calls( [mock.call(1), mock.call(2), mock.call(3), mock.call(4)], any_order=False) block1, block2, block3 = Block.objects.all().order_by("height") self.assertEqual(block1.height, 1) self.assertTrue(block1.pool_block) self.assertEqual(block1.subsidy, 100) self.assertEqual(block1.process_status, 'OP') self.assertEqual(block1.miner, None) self.assertEqual(block1.network, 'test') self.assertEqual(block1.recipient, 'POOLADDR') self.assertEqual(block1.inserted_at, test_block_time1) self.assertEqual(block2.height, 2) self.assertTrue(block2.pool_block) self.assertEqual(block2.subsidy, 500) self.assertEqual(block2.process_status, 'OP') self.assertEqual(block2.miner, self.miner) self.assertEqual(block2.network, 'test') self.assertEqual(block2.recipient, 'POOLADDR') self.assertEqual(block2.inserted_at, test_block_time2) self.assertEqual(block3.height, 3) self.assertFalse(block3.pool_block) self.assertEqual(block3.subsidy, 200) self.assertEqual(block3.process_status, 'OP') self.assertEqual(block3.miner, None) self.assertEqual(block3.network, 'test') self.assertEqual(block3.recipient, 'rec') self.assertEqual(block3.inserted_at, test_block_time3) # execute a second time mock_subsidy.side_effect = [{ 'subsidy': 55, 'minerguid': 'unknown', 'recipient': 'xxx' }, None] find_new_blocks('test') # multiple times called with "4", as the first call # asks for "4" and fails on that! mock_subsidy.assert_has_calls([ mock.call(1), mock.call(2), mock.call(3), mock.call(4), mock.call(4), mock.call(5) ], any_order=False) block1, block2, block3, block4 = Block.objects.all().order_by( "height") self.assertEqual(block4.height, 4) self.assertFalse(block4.pool_block) self.assertEqual(block4.subsidy, 55) self.assertEqual(block4.process_status, 'OP') self.assertEqual(block4.miner, None) self.assertEqual(block4.network, 'test') self.assertEqual(block4.recipient, 'xxx') self.assertEqual(block4.inserted_at, test_block_time4) def test_invalid_subsidy(self): with mock.patch('purepool.models.block.tasks.BiblePayRpcClient.subsidy') as mock_subsidy, \ mock.patch('purepool.models.block.tasks.get_block_time', return_value=self.block_time): # the mock client will return the result for two block mock_subsidy.side_effect = [{'something': 'else'}] find_new_blocks('test') self.assertEqual(Block.objects.all().count(), 0) def test_blocknotfound(self): with mock.patch('purepool.models.block.tasks.BiblePayRpcClient.subsidy') as mock_subsidy, \ mock.patch('purepool.models.block.tasks.get_block_time', return_value=self.block_time): mock_subsidy.side_effect = BlockNotFound() find_new_blocks('test') @override_settings(POOL_ADDRESS={'test': 'POOLADDR'}) def test_mark_as_processed(self): with mock.patch('purepool.models.block.tasks.BiblePayRpcClient.subsidy') as mock_subsidy, \ mock.patch('purepool.models.block.tasks.get_block_time', return_value=self.block_time): # the mock client will return the result for two block mock_subsidy.side_effect = [{ 'subsidy': 100, 'minerguid': 'unknown', 'recipient': 'POOLADDR' }, None] find_new_blocks('test', mark_as_processed=True) block1 = Block.objects.all().order_by("height")[0] self.assertEqual(block1.height, 1) self.assertTrue(block1.pool_block) self.assertEqual(block1.subsidy, 100) self.assertEqual(block1.process_status, 'FI') self.assertEqual(block1.miner, None) self.assertEqual(block1.network, 'test') self.assertEqual(block1.recipient, 'POOLADDR') @override_settings(POOL_ADDRESS={'test': 'POOLADDR'}) def test_max_height(self): with mock.patch('purepool.models.block.tasks.BiblePayRpcClient.subsidy') as mock_subsidy, \ mock.patch('purepool.models.block.tasks.get_block_time', return_value=self.block_time): # the mock client will return the result for two block mock_subsidy.side_effect = [{ 'subsidy': 100, 'minerguid': 'unknown', 'recipient': 'POOLADDR' }, { 'subsidy': 100, 'minerguid': 'unknown', 'recipient': 'POOLADDR' }, { 'subsidy': 100, 'minerguid': 'unknown', 'recipient': 'POOLADDR' }, None] find_new_blocks('test', max_height=1) self.assertEqual(Block.objects.all().count(), 1) block1 = Block.objects.all().order_by("height")[0] self.assertEqual(block1.height, 1) self.assertTrue(block1.pool_block) self.assertEqual(block1.subsidy, 100) self.assertEqual(block1.process_status, 'OP') self.assertEqual(block1.miner, None) self.assertEqual(block1.network, 'test') self.assertEqual(block1.recipient, 'POOLADDR')
def setUp(self): self.miner = Miner(address='123456', network="main") self.miner.save() self.worker = Worker(miner=self.miner, name="abc") self.worker.save()
def shareout_next_block(network, block_height=None, dry_run=False): """ Tries to find the oldest block that had matured and was not yet processed for shares. Optional, a specific block can be given. This task takes this block, calculates the shares of all users that contributed to the block and creates the transactions with there bbps. Important: The bbp will not send here, this is an extra step, done when the transaction limit is reached for a user Dry run will not save anything to the database. """ if settings.TASK_DEBUG: print("Debug | ", "Shareout started with network", network, "on block ", block_height, " in dry-run", dry_run) # we only start here, if no block is currently processed # not important in dry_run if not dry_run and Block.objects.filter( network=network, pool_block=True, process_status='PS').count() > 0: if settings.TASK_DEBUG: print("Debug | ", "Another block is currently processed/has status 'PS'") return # try to find the oldest block then is OLDER then 1 day # (so it had matured -> the network had accepted it) and take it age = timezone.now() - datetime.timedelta( hours=settings.POOL_BLOCK_MATURE_HOURS[network]) if block_height is None: lowest_pool_waiting_height = Block.objects.filter( network=network, pool_block=True, process_status='BP', inserted_at__lt=age).aggregate(Min('height'))['height__min'] if lowest_pool_waiting_height is None: # no unprocessed block found return else: lowest_pool_waiting_height = block_height block = Block.objects.get(network=network, height=lowest_pool_waiting_height) if settings.TASK_DEBUG: print("Debug | ", "Loaded block from database:", block.height, block.network, block.process_status, block.inserted_at) # before we start, we mark the block as in-process of the shares with transaction.atomic(): block.process_status = 'PS' # Processing shares if not dry_run: block.save() # if we found a block, we ensure that is still ours! client = BiblePayRpcClient(network=network) subsidy = client.subsidy(lowest_pool_waiting_height) if settings.TASK_DEBUG: print("Debug | ", "Requested subsidy: ", subsidy) if subsidy.get('recipient') != settings.POOL_ADDRESS[network]: block.process_status = 'ST' # stale if not dry_run: block.save() return # now we count the users solutions for the block # Important: Do not remove the ".order_by()", as it is required, or the result # will be wrong (seems to be a django problem) qs = Solution.objects.filter(network=network, block=block, ignore=False) if not dry_run: # in reall live, we only want entries that where not already processed qs = qs.filter(processed=False) solution_counts = qs.values('miner_id').annotate( total=Count('miner_id')).order_by() # with that, we first calculate the total amount of relevant shares total_count = 0 for solution_count in solution_counts: total_count += solution_count['total'] if settings.TASK_DEBUG: print("Debug | ", "Solution count is ", total_count) print("Debug | ", "Miner/solution count is ", len(solution_counts)) # if there are no shares, then there is nothing todo here anymore if total_count == 0: block.process_status = 'FI' # finished if not dry_run: block.save() return # same if the block.subsidy is buggy if block.subsidy == 0: block.process_status = 'FI' # finished if not dry_run: block.save() return # before we do the share calculation, we substract the fee from the subsidy miner_subsidy = block.subsidy if settings.POOL_FEE_PERCENT > 0: miner_subsidy = calculate_miner_subsidy(block.subsidy) if settings.TASK_DEBUG: print("Debug | ", "Miner subsidy is ", miner_subsidy) # calculcation of the amount of bbp per user based on the solutions of the block subsidy_per_solution = miner_subsidy / total_count if settings.TASK_DEBUG: print("Debug | ", "Subsidy per solution is ", subsidy_per_solution, "with a total of", (subsidy_per_solution * total_count)) added_amount = 0 # and now we add the transactions that add the coins to the user # they are not send to the user here, that will be done by a different script with transaction.atomic(): for solution_count in solution_counts: user_subsidy = subsidy_per_solution * solution_count['total'] inote = 'BLOCK:' + str(block.height) + '|SOLUTIONS:' + str( solution_count['total']) tx = Transaction( network=network, miner_id=solution_count['miner_id'], amount=user_subsidy, category='MS', # some notes for the user and some for us note='Share for block %s' % block.height, internal_note=inote, ) if not dry_run: tx.save() added_amount += user_subsidy # last but not least, we mark the block and the solutions as processed if not dry_run: Solution.objects.filter(network=network, processed=False, block=block).update(processed=True) # and we mark the block as finished block.process_status = 'FI' # finished if not dry_run: block.save() if settings.TASK_DEBUG: print("Debug | ", "Created transaction with a total amount of ", added_amount) # last, we update the user balances. We do this in a new step, as the step before is more important # and should be done as fast as possible # We do not load the miner from the database, we only update it. This is faster if not dry_run: update_list = [] with transaction.atomic(): for solution_count in solution_counts: value = Miner.calculate_miner_balance( network, solution_count['miner_id']) Miner.objects.filter(pk=solution_count['miner_id']).update( balance=value)
def setUp(self): self.miner = Miner(rating=0) self.miner.save()
class validate_solutionTestCase(TestCase): def setUp(self): self.miner = Miner() self.miner.save() self.worker = Worker(miner=self.miner) self.worker.save() self.solution_string = SolutionString() self.solution_string.content = { 'transaction_hex': '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05026e4b0103ffffffff01ca6940057a0100001976a914e83c22b58de63a91952524084f46415c985d715c88acfdce013c5645523e312e302e382e363c2f5645523e3c4d494e4552475549443e65656635636263622d663637332d343230332d613739312d6637373362313737663164663c2f4d494e4552475549443e3c706f6c6d6573736167653e666531313263363532643964643063663436326135333762636466363561323537663461613331303032396666373432383964396366623665303161396662623c2f706f6c6d6573736167653e3c706f6c7765696768743e35363438302e35313c2f706f6c7765696768743e3c706f6c616d6f756e743e31363437342e30303c2f706f6c616d6f756e743e3c706f6c6176676167653e332e3432393c2f706f6c6176676167653e3c5349475f303e494d3736436d344e57376e554e78614e5050797662373473424d437945586e314d49347339376b4f334d475a6469672f496a59486c48594139637346616b3769756451536c6769596f643366756d4c2f44797075706e593d3c2f5349475f303e3c5349475f313e494e684d7a47487658727a4b654366424e384d4c584671466b45495a36455758694a572f6535334e73384e4c5652755274535877395830337937452b46447a7a68455762744756543868307a42477751484c33305930513d3c2f5349475f313e00000000', 'thread_hash_counter': '332694', 'prev_block_time': '1518041437', 'prev_height': '19309', 'nonce': '14217', 'block_hash': '4adfaf0c3ad50afecad53ad1e57340e9735bca7d104b2b3565835a346e1c6c96', 'miner_id': self.miner.id, 'work_id': 'b0181b3a-9868-4139-bef5-8c7e5d4239f4', 'block_time': '1518041523', 'thread_id': '0', 'timer_start': '1518037739857', 'thread_start': '1518040817888', 'bible_hash': '0000000e5bced1fccc7110dfd386cf461b82852ce4eec5e124ca8f5e5bcc5a11', 'hash_counter': '1769512', 'timer_end': '1518041527556', 'block_hex': '000000209928ce1b5ba829fde591237d3876df45daa2dd30ec31805b43dd6b972eae9aff3fab6ced6b34254aeb8c7f004cb82178984dbf22ea5c5316ac33ae6ec90ef17db3797b5aa5aa081d893700000201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05026e4b0103ffffffff01ca6940057a0100001976a914e83c22b58de63a91952524084f46415c985d715c88acfdce013c5645523e312e302e382e363c2f5645523e3c4d494e4552475549443e65656635636263622d663637332d343230332d613739312d6637373362313737663164663c2f4d494e4552475549443e3c706f6c6d6573736167653e666531313263363532643964643063663436326135333762636466363561323537663461613331303032396666373432383964396366623665303161396662623c2f706f6c6d6573736167653e3c706f6c7765696768743e35363438302e35313c2f706f6c7765696768743e3c706f6c616d6f756e743e31363437342e30303c2f706f6c616d6f756e743e3c706f6c6176676167653e332e3432393c2f706f6c6176676167653e3c5349475f303e494d3736436d344e57376e554e78614e5050797662373473424d437945586e314d49347339376b4f334d475a6469672f496a59486c48594139637346616b3769756451536c6769596f643366756d4c2f44797075706e593d3c2f5349475f303e3c5349475f313e494e684d7a47487658727a4b654366424e384d4c584671466b45495a36455758694a572f6535334e73384e4c5652755274535877395830337937452b46447a7a68455762744756543868307a42477751484c33305930513d3c2f5349475f313e00000000010000000223e3f54cbfd562a065218f2f5be70a9d22e6ff7820dd0d1f701a53afb53767170000000049483045022100d612e1ee658823964ebdc3dedcecf2e9c19c7a9891ba264b8ba170cdfed58fbd02201d4de4c922afa8c218aa8fe6b73eadd62f00109cd777b3f7489f50eab83d3da301feffffff3fab86d7035b899793e1264899b1838fd6b988a7adc1866365dbd06250c65f260000000048473044022005004171fbc47a417c5c68e3abfd8a76e375029866b779ae117730d61ff64bab0220268e22a951608a7050747fa9e373d7610b11eb3de663f954affdf394941b777501feffffff0225b74458390000001976a9146ebc0349fad92dbb1b277ea9209609b5a485e4f988ac1f3c706f6c7765696768743e31343031312e30303c2f706f6c7765696768743ed6e9123b46010000232103dbeb934062e53b5deef24a89825b225eeea09c31037693ac7d192c5c581e1fbcac1f3c706f6c7765696768743e31343031312e30303c2f706f6c7765696768743e6d4b0000' } def test_basic(self): # work missing with self.assertRaises(UnknownWork): validate_solution('test', self.solution_string) # check_hashtarget fails work = Work( pk='b0181b3a-9868-4139-bef5-8c7e5d4239f4', hash_target= "0000000111100000000000000000000000000000000000000000000000000000", worker=self.worker, ip="1.1.1.1", network="test") work.save() with self.assertRaises(HashTargetExceeded): validate_solution('test', self.solution_string) # client.bible_hash returns different bible hash work.hash_target = '0000001111000000000000000000000000000000000000000000000000000000' work.save() with mock.patch( 'purepool.models.solution.tasks.BiblePayRpcClient.bible_hash', return_value="1234"): with self.assertRaises(BibleHashWrong): validate_solution('test', self.solution_string) # from here on, we fake a valid answer for the bible_hash calculation, so that # succeed with mock.patch( 'purepool.models.solution.tasks.BiblePayRpcClient.bible_hash', return_value= "0000000e5bced1fccc7110dfd386cf461b82852ce4eec5e124ca8f5e5bcc5a11" ): # fail if the target address in the transaction is not from the pool trans_result = {'recipient': 'yiCwAb9qeaQqzDX5jQZJgBQ9mRy2aqk2Tb'} with mock.patch( 'purepool.models.solution.tasks.BiblePayRpcClient.hexblocktocoinbase', return_value=trans_result): with self.settings(POOL_ADDRESS={ 'test': 'ABCDEFG', 'cpid_sig_valid': True }): with self.assertRaises(TransactionTampered): validate_solution('test', self.solution_string) # fail if this is an invalid TX with mock.patch( 'purepool.models.solution.tasks.BiblePayRpcClient.hexblocktocoinbase', return_value=trans_result) as mock_hexblocktocoinbase: mock_hexblocktocoinbase.side_effect = TypeError() with self.assertRaises(TransactionInvalid): validate_solution('test', self.solution_string) # the TX is valid here, but the nonce is not right! with self.settings(POOL_ADDRESS={'test': 'ABCDEFG'}): trans_result = { 'recipient': 'ABCDEFG', 'cpid_sig_valid': True, 'cpid_legal': True } with mock.patch( 'purepool.models.solution.tasks.BiblePayRpcClient.hexblocktocoinbase', return_value=trans_result): with mock.patch( 'purepool.models.solution.tasks.BiblePayRpcClient.pinfo', return_value={ 'pinfo': 3, 'height': 0 }): with self.assertRaises(TransactionTampered): validate_solution('test', self.solution_string) # Here the prev_height was faked with self.settings(POOL_ADDRESS={'test': 'ABCDEFG'}): trans_result = { 'recipient': 'ABCDEFG', 'cpid_sig_valid': True, 'cpid_legal': True } with mock.patch( 'purepool.models.solution.tasks.BiblePayRpcClient.hexblocktocoinbase', return_value=trans_result): with mock.patch( 'purepool.models.solution.tasks.BiblePayRpcClient.pinfo', return_value={ 'pinfo': 999999, 'height': 19 }): with self.assertRaises(TransactionTampered): validate_solution('test', self.solution_string) # now cpid_sig_valid is missing -> old biblepay server client with self.settings(POOL_ADDRESS={'test': 'ABCDEFG'}): trans_result = {'recipient': 'ABCDEFG'} with mock.patch( 'purepool.models.solution.tasks.BiblePayRpcClient.hexblocktocoinbase', return_value=trans_result): with mock.patch( 'purepool.models.solution.tasks.BiblePayRpcClient.pinfo', return_value={ 'pinfo': 999999, 'height': 19 }): with self.assertRaises(Biblepayd_Outdated): validate_solution('test', self.solution_string) # and now cpid_sig_valid is False with self.settings(POOL_ADDRESS={'test': 'ABCDEFG'}): trans_result = { 'recipient': 'ABCDEFG', 'cpid_sig_valid': True, 'cpid_legal': False } with mock.patch( 'purepool.models.solution.tasks.BiblePayRpcClient.hexblocktocoinbase', return_value=trans_result): with mock.patch( 'purepool.models.solution.tasks.BiblePayRpcClient.pinfo', return_value={ 'pinfo': 999999, 'height': 19 }): with self.assertRaises(Illegal_CPID): validate_solution('test', self.solution_string) # cpid_legal indicates if the user was in the last payout for Rosetta, plus it checks if the user had just solved a block # and can't solve a new one for the next 3 blocks with self.settings(POOL_ADDRESS={'test': 'ABCDEFG'}): trans_result = { 'recipient': 'ABCDEFG', 'cpid_sig_valid': False, 'cpid_legal': True } with mock.patch( 'purepool.models.solution.tasks.BiblePayRpcClient.hexblocktocoinbase', return_value=trans_result): with mock.patch( 'purepool.models.solution.tasks.BiblePayRpcClient.pinfo', return_value={ 'pinfo': 999999, 'height': 19 }): with self.assertRaises(Invalid_CPID): validate_solution('test', self.solution_string) # and now, with everything right, it should succeed with self.settings(POOL_ADDRESS={'test': 'ABCDEFG'}): trans_result = { 'recipient': 'ABCDEFG', 'cpid_sig_valid': True, 'cpid_legal': True } with mock.patch( 'purepool.models.solution.tasks.BiblePayRpcClient.hexblocktocoinbase', return_value=trans_result): with mock.patch( 'purepool.models.solution.tasks.BiblePayRpcClient.pinfo', return_value={ 'pinfo': 999999, 'height': 19309 }): self.assertTrue( validate_solution('test', self.solution_string))
def setUp(self): self.miner = Miner() self.miner.save() self.worker = Worker(miner=self.miner) self.worker.save()
class calculate_multiplyTestCase(TestCase): def setUp(self): self.miner = Miner() self.miner.save() self.solution_string = SolutionString() self.solution_string.content = { 'miner_id': self.miner.id, } def test_regular(self): self.miner.percent_ratio = 100 self.miner.save() self.assertEqual(calculate_multiply(self.solution_string), 1) def test_bad(self): self.miner.percent_ratio = 400 self.miner.save() with mock.patch('random.randrange', return_value=200): # multiply is inactive right now, it always returns 1 #self.assertEqual(calculate_multiply(self.solution_string), 0) self.assertEqual(calculate_multiply(self.solution_string), 1) with mock.patch('random.randrange', return_value=50): self.assertEqual(calculate_multiply(self.solution_string), 1) def test_good(self): self.miner.percent_ratio = 9 self.miner.save() # multiply is inactive right now, it always returns 1 #self.assertEqual(calculate_multiply(self.solution_string), 4) self.assertEqual(calculate_multiply(self.solution_string), 1) self.miner.percent_ratio = 30 self.miner.save() # multiply is inactive right now, it always returns 1 #self.assertEqual(calculate_multiply(self.solution_string), 3) self.assertEqual(calculate_multiply(self.solution_string), 1) self.miner.percent_ratio = 50 self.miner.save() # multiply is inactive right now, it always returns 1 #self.assertEqual(calculate_multiply(self.solution_string), 2) self.assertEqual(calculate_multiply(self.solution_string), 1)
class process_solutionTestCase(TestCase): def setUp(self): self.miner = Miner() self.miner.save() self.worker = Worker(miner=self.miner) self.worker.save() self.work = Work( hash_target= "0000000111100000000000000000000000000000000000000000000000000000", worker=self.worker, ip="1.1.1.1") self.work.save() self.solution_string = SolutionString() self.solution_string.content = { 'transaction_hex': 'TransHex', 'thread_hash_counter': '332694', 'prev_block_time': '1518041437', 'prev_height': '19309', 'nonce': '14217', 'block_hash': 'ABCD', 'miner_id': self.miner.id, 'work_id': self.work.id, 'block_time': '1518041523', 'thread_id': '0', 'timer_start': '1518037739857', 'thread_start': '1518040817888', 'bible_hash': '0000000e5bced1fccc7110dfd386cf461b82852ce4eec5e124ca8f5e5bcc5a11', 'hash_counter': '1769512', 'timer_end': '1518041527556', 'block_hex': 'BlockHex' } self.solution_s = self.solution_string.as_string() def test_valid(self): self.assertEqual(len(Solution.objects.all()), 0) self.assertEqual(len(RejectedSolution.objects.all()), 0) with mock.patch('purepool.models.solution.tasks.validate_solution', return_value=True): process_solution('test', self.solution_s) self.assertEqual(len(RejectedSolution.objects.all()), 0) self.assertEqual(len(Solution.objects.all()), 1) solution = Solution.objects.all()[0] self.assertEqual(solution.network, 'test') self.assertEqual(solution.miner_id, self.miner.id) self.assertEqual(solution.work_id, self.work.id) self.assertEqual(solution.bible_hash, self.solution_string.get_bible_hash()) self.assertEqual(solution.solution, '') #self.solution_s) self.assertEqual(solution.hps, 467) def test_valid_multiply(self): self.assertEqual(len(Solution.objects.all()), 0) self.assertEqual(len(RejectedSolution.objects.all()), 0) with mock.patch('purepool.models.solution.tasks.validate_solution', return_value=True): with mock.patch( 'purepool.models.solution.tasks.calculate_multiply', return_value=3): process_solution('test', self.solution_s) self.assertEqual(len(RejectedSolution.objects.all()), 0) self.assertEqual(len(Solution.objects.all()), 3) solution = Solution.objects.all()[0] self.assertEqual(solution.network, 'test') self.assertEqual(solution.miner_id, self.miner.id) self.assertEqual(solution.work_id, self.work.id) self.assertEqual(solution.bible_hash, self.solution_string.get_bible_hash()) self.assertEqual(solution.solution, '') # self.solution_s) self.assertEqual(solution.hps, 467) def test_invalid(self): self.assertEqual(len(Solution.objects.all()), 0) self.assertEqual(len(RejectedSolution.objects.all()), 0) with mock.patch('purepool.models.solution.tasks.validate_solution', return_value=False) as mock_validate_solution: mock_validate_solution.side_effect = BibleHashWrong with self.assertRaises(BibleHashWrong): process_solution('test', self.solution_s) self.assertEqual(len(RejectedSolution.objects.all()), 1) self.assertEqual(len(Solution.objects.all()), 0) rsolution = RejectedSolution.objects.all()[0] self.assertEqual(rsolution.network, 'test') self.assertEqual(rsolution.miner_id, self.miner.id) self.assertEqual(rsolution.work_id, self.work.id) self.assertEqual(rsolution.bible_hash, self.solution_string.get_bible_hash()) self.assertEqual(rsolution.solution, self.solution_s) self.assertEqual(rsolution.hps, 0)
def send_autopayments(network): """ Looks into the miner list and finds all miners that have a balance greater than settings.POOL_MINIMUM_AUTOSEND """ # no autosend is done if the miner has a balance below # this value minimum = settings.POOL_MINIMUM_AUTOSEND[network] # miners of the network with more then the minimum balance miners = Miner.objects.filter(balance__gt=minimum, network=network).values('id', 'address') client = BiblePayRpcClient(network=network) # the system will only do the transactions for # this amount of miners before this task is closed # the next task will go on from then on max_miners = 10 miner_pos = 0 for miner in miners: # we only send payments for miners who hadn't a payment in the last 12 hours last_trans_dt = timezone.now() - datetime.timedelta(hours=12) last_trans_count = Transaction.objects.filter( miner_id=miner['id'], network=network, category='TX', inserted_at__gt=last_trans_dt).count() if last_trans_count > 0: continue miner_pos += 1 with transaction.atomic(): # for security reasons, we recalculate the balance, # as the miner table can be changed by the frontend value = Miner.calculate_miner_balance(network, miner['id']) # if all is fine, we send out the bbp if value > minimum: tx_id = None try: tx_id = client.sendtoaddress(miner['address'], value) except Exception as e: error_message = ' # '.join([str(e), str(type(e))]) + "\n" error_message += str(traceback.extract_stack()) + "\n" error_message += str(traceback.format_stack()) # we should log the error if something goes wrong transerror = TransactionError( network=network, miner_id=miner['id'], amount=(value * -1), error_message=error_message, ) transerror.save() # transaction failed? Then we skip this user this time if tx_id is None: continue internal_note = 'TX_ID:%s' % tx_id tx = Transaction( network=network, miner_id=miner['id'], category='TX', # outgoing transaction # We substract the amount here, so it must be negative (55 -> -55) amount=(value * -1), # biblepay transaction tx=tx_id, # some notes for the user and some for us note='Autosend', internal_note=internal_note, ) tx.save() # no value should be on the account anymore # but we better calculate it, if something had changed value = Miner.calculate_miner_balance(network, miner['id']) # added to prevent a problem with to fast and many transactions # in a short time time.sleep(5) # we update the miner with the new balance # even if no bbp was send (because of wrong values in the db). We # at least fix the value then Miner.objects.filter(pk=miner['id'], network=network).update(balance=value) # we end after we reached our max for this task if miner_pos == max_miners: break
class GetHashTargetTestCase(TestCase): def setUp(self): self.miner = Miner(rating=0) self.miner.save() def test_basic(self): self.assertEqual(GetHashTarget(self.miner.id, 'main'), '0000011110000000000000000000000000000000000000000000000000000000') # NOTE: In previos versions, the rating changed the hash # But now, we drop them in the validate_solution task. This test ensures that the new behavior is working self.miner.rating = -1 self.miner.save() self.assertEqual(GetHashTarget(self.miner.id, 'main'), '0000011110000000000000000000000000000000000000000000000000000000') self.miner.rating = -2 self.miner.save() self.assertEqual(GetHashTarget(self.miner.id, 'main'), '0000011110000000000000000000000000000000000000000000000000000000') self.miner.rating = 1 self.miner.save() self.assertEqual(GetHashTarget(self.miner.id, 'main'), '0000011110000000000000000000000000000000000000000000000000000000') self.miner.rating = 2 self.miner.save() self.assertEqual(GetHashTarget(self.miner.id, 'main'), '0000011110000000000000000000000000000000000000000000000000000000') self.miner.rating = 3 self.miner.save() self.assertEqual(GetHashTarget(self.miner.id, 'main'), '0000011110000000000000000000000000000000000000000000000000000000')