def setUp(self): from mineable_token_info import MineableTokenInfo from web3 import Web3 self.m = MineableTokenInfo(config.TOKEN_ETH_ADDRESS) self.m.update()
def main(): import argparse import os # TODO: make client NOT global. global client, apis parser = argparse.ArgumentParser(description='{} v{}'.format( _PROGRAM_NAME, __version__), epilog='<3 0x1d00ffff') group = parser.add_mutually_exclusive_group() group.add_argument('--command_test', action='store_true', default=False, help=("If set, don't connect to Discord - instead " "run a CLI interface to allow command tests.")) group.add_argument('--self_test', action='store_true', default=False, help=("Run unittests")) group.add_argument('--speed_test', action='store_true', default=False, help=("Run command processing speed test")) group.add_argument('--fuzz_test', action='store_true', default=False, help=("Run command processing fuzz test")) group.add_argument('--version', action='version', version='%(prog)s v{}'.format(__version__)) parser.add_argument('--verbose', action='store_true', help=("Enable detailed debug messages")) args = parser.parse_args() start_time = time.time() if args.self_test or args.command_test or args.speed_test or args.fuzz_test: logging.basicConfig(level=logging.INFO) config.DATA_FOLDER = './test_data/databases/' if not os.path.exists(config.DATA_FOLDER): os.makedirs(config.DATA_FOLDER) setup_logging(os.path.join(config.DATA_FOLDER, 'debug.log'), verbose=args.verbose) token = MineableTokenInfo(config.TOKEN_ETH_ADDRESS) storage = Storage(config.DATA_FOLDER) gas_price_api = GasPriceAPI() exchange_manager = exchanges.MultiExchangeManager([ exchanges.CoinMarketCapAPI(config.TOKEN_SYMBOL), # exchanges.CoinMarketCapAPI('ETH'), # exchanges.CoinMarketCapAPI('BTC'), exchanges.LiveCoinWatchAPI('ETH'), exchanges.LiveCoinWatchAPI('BTC'), # 5/4/20 removed IDEX. They seem to only partially (?) support 0xBTC. They are also a CEX masquerading as a DEX, which is unethical. # exchanges.IDEXAPI(config.TOKEN_SYMBOL), exchanges.MercatoxAPI(config.TOKEN_SYMBOL), # 9/10/20 remove uniswap v1. All liquidity (except $200) has moved to v2 # exchanges.Uniswapv1API(config.TOKEN_SYMBOL), exchanges.Uniswapv2API(config.TOKEN_SYMBOL), # 3/13/20 removed 0xChange. Will re-enable in the future. # exchanges.ZxchangeAPI(config.TOKEN_SYMBOL), # 2/12/20 removed coinexchange. homepage says closed. # exchanges.CoinExchangeAPI(config.TOKEN_SYMBOL), # 2/12/20 removed enclaves. blocks all usa traffic. # exchanges.EnclavesAPI(config.TOKEN_SYMBOL), # 2/12/20 removed ethex, they might be out of business. homepage says check later. # exchanges.EthexAPI(config.TOKEN_SYMBOL), # 2/12/20 removed forkdelta, need new api. 7/26/20: reenabled forkdelta. 5/21/21 removed forkdelta. no volume in 6 months # exchanges.ForkDeltaAPI(config.TOKEN_SYMBOL, storage), # 8/18/21 remove balancer - no liquidity # exchanges.BalancerAPI(config.TOKEN_SYMBOL), # exchanges.HotbitAPI(config.TOKEN_SYMBOL), # 2/12/20 removed merklex. seems to have rebranded to nitrade. # exchanges.MerkleXAPI(config.TOKEN_SYMBOL), # 9/22/20 added swapmatic, 11/25/21 disable due to lack of reliable polygon provider, 12/21/21 re-enable - alchemyapi.io works exchanges.SwapmaticAPI(config.TOKEN_SYMBOL), # 4/03/21 added quickswap, 11/25/21 disable due to lack of reliable polygon provider, 12/21/21 re-enable - alchemyapi.io works exchanges.QuickSwapAPI(config.TOKEN_SYMBOL), # 5/30/21 added uniswap v3 exchanges.Uniswapv3API(config.TOKEN_SYMBOL), # 8/18/21 added sushiswap on polygon, 11/25/21 disable due to lack of reliable polygon provider, 12/21/21 re-enable - alchemyapi.io works exchanges.SushiSwapPolygonAPI(config.TOKEN_SYMBOL), ]) if args.self_test or args.command_test or args.speed_test or args.fuzz_test: client = MockClient() # sets global var apis = APIWrapper(client, storage, exchange_manager, token, gas_price_api, start_time) if args.self_test: all_self_tests.run_all() if args.command_test: try: asyncio.get_event_loop().run_until_complete(command_test()) except (SystemExit, KeyboardInterrupt): return if args.speed_test: speed_test() if args.fuzz_test: try: all_self_tests.run_command_fuzzer() except (SystemExit, KeyboardInterrupt): return else: connect_to_discord_and_run_forever(storage, exchange_manager, token, gas_price_api, start_time)
class TestMineableTokenInfo(unittest.TestCase): def setUp(self): from mineable_token_info import MineableTokenInfo from web3 import Web3 self.m = MineableTokenInfo(config.TOKEN_ETH_ADDRESS) self.m.update() @unittest.skipIf( config.TOKEN_SYMBOL != "0xBTC", "This test assumes 0xBTC and must be modified for other currencies") def test_reading_0xbtc_values(self): m = self.m self.assertIsNotNone(m.symbol) self.assertIsNotNone(m.total_supply) self.assertIsNotNone(m.last_difficulty_start_block) self.assertIsNotNone(m.mining_target) self.assertIsNotNone(m.difficulty) self.assertIsNotNone(m.tokens_minted) self.assertIsNotNone(m.addr_0_balance) self.assertIsNotNone(m.seconds_since_readjustment) self.assertIsNotNone(m.seconds_per_reward) self.assertIsNotNone(m.era) self.assertIsNotNone(m.estimated_hashrate_since_readjustment) # this test fails - infura v3 api does not support the calls necessary #self.assertIsNotNone(m.estimated_hashrate_24h) self.assertIsNotNone(m.max_supply_for_era) self.assertIsNotNone(m.reward) self.assertIsNotNone(m.seconds_remaining_in_era) self.assertTrue(m.symbol == "0xBTC") self.assertTrue(19000000 < m.total_supply < 20999983.97) self.assertTrue(6560003 < m.last_difficulty_start_block < 1e10) self.assertTrue(m.min_target <= m.mining_target <= m.max_target) self.assertTrue(0 < m.difficulty < 1e30) self.assertTrue(3302800 < m.tokens_minted < 21000000.1) self.assertTrue(0 < m.addr_0_balance < 2000000) self.assertTrue( 0 < m.seconds_since_readjustment < 60 * 60 * 24 * 31 * 12) self.assertTrue(0 < m.seconds_per_reward < 60 * 60 * 24 * 31) self.assertTrue( 0 < m.seconds_until_readjustment < 60 * 60 * 24 * 31 * 12) self.assertTrue(0 <= m.era < 40) self.assertTrue(0 < m.max_supply_for_era < 10500001) self.assertTrue(0 < m.reward <= 50.0) self.assertTrue(0 <= m.seconds_remaining_in_era < 1e30) self.assertTrue( 100000 < m.estimated_hashrate_since_readjustment < 1e30) # these tests fail - infura v3 api does not support the calls necessary # to support 24-hour average hashrate anymore, unfortunately ## self.assertTrue(100000 < m.estimated_hashrate_24h < 1e30) ## hashrate_over_2_days = m._estimated_hashrate_n_days(2) ## self.assertTrue(100000 < hashrate_over_2_days < 1e30) ## # this check technically could fail, but it should be unlikely enough ## self.assertTrue(m.estimated_hashrate_24h != hashrate_over_2_days) events_in_last_2_days = m.get_events_last_n_days(2) self.assertIsNotNone(events_in_last_2_days) self.assertTrue(len(events_in_last_2_days) > 0) self.assertTrue(events_in_last_2_days[-1]['type'] in ['mint', 'transfer', 'approve']) def test_hashing_nonces(self): from web3 import Web3 nonces = [b'\x00', b'\x00\x0F', b'test'] for n in nonces: with self.subTest(nonce=n): nonce, digest = self.m.get_digest_for_nonce( n, "0x0000000000000000000000000000000000000000") self.assertIsNotNone(nonce) self.assertEqual(len(nonce), 32) self.assertIsNotNone(digest) self.assertTrue(self.m.min_target < Web3.toInt(digest)) nonces = ["0x41", "65", "A"] digests = [] for n in nonces: with self.subTest(nonce=n): nonce, digest = self.m.get_digest_for_nonce_str( n, "0x0000000000000000000000000000000000000000") self.assertIsNotNone(nonce) self.assertEqual(len(nonce), 32) self.assertIsNotNone(digest) self.assertNotEqual(digest, b'\x00') self.assertNotEqual(digest, b'') self.assertTrue(self.m.min_target < Web3.toInt(digest)) digests.append(digest) self.assertEqual(digests[0], digests[1]) self.assertEqual(digests[1], digests[2]) nonce, digest_short = self.m.get_digest_for_nonce_str( "0xFF1234", "0x0000000000000000000000000000000000000000") self.assertEqual( nonce, Web3.toBytes( hexstr= '0xff12340000000000000000000000000000000000000000000000000000000000' )) self.assertIsNotNone(digest_short) self.assertTrue(self.m.min_target < Web3.toInt(digest_short)) nonce, digest_long = self.m.get_digest_for_nonce_str( "0xff12340000000000000000000000000000000000000000000000000000000000ab", "0x0000000000000000000000000000000000000000") self.assertEqual( nonce, Web3.toBytes( hexstr= "0xff12340000000000000000000000000000000000000000000000000000000000" )) self.assertIsNotNone(digest_long) self.assertTrue(self.m.min_target < Web3.toInt(digest_long)) self.assertEqual(digest_short, digest_long) nonce, digest = self.m.get_digest_for_nonce_str( "0x03000000000000000440a2682657259316000000e87905d96943030a90de3e74", "0x540d752A388B4fC1c9Deeb1Cd3716A2B7875D8A6", "0x3b0ec88154c8aecbc7876f50d8915ef7cd6112a604cad4f86f549d5b9eed369a" ) self.assertEqual( nonce, Web3.toBytes( hexstr= "0x03000000000000000440a2682657259316000000e87905d96943030a90de3e74" )) self.assertEqual( digest, Web3.toBytes( hexstr= "0x000000000a7ddfa621b3a1aa9605da95185cb75a6a91bafb2976f36606c4d5e2" ))
def main(): import argparse import os global client, apis parser = argparse.ArgumentParser(description='{} v{}'.format( _PROGRAM_NAME, _VERSION), epilog='<3 0x1d00ffff') parser.add_argument('--command_test', action='store_true', default=False, help=("If set, don't connect to Discord - instead " "run a CLI interface to allow command tests.")) parser.add_argument('--self_test', action='store_true', default=False, help=("Run unittests")) parser.add_argument('--speed_test', action='store_true', default=False, help=("Run command processing speed test")) parser.add_argument('--fuzz_test', action='store_true', default=False, help=("Run command processing fuzz test")) parser.add_argument('--verbose', action='store_true', help=("Enable detailed debug messages")) parser.add_argument('--version', action='version', version='%(prog)s v{}'.format(_VERSION)) args = parser.parse_args() start_time = time.time() if args.self_test or args.command_test or args.speed_test or args.fuzz_test: config.DATA_FOLDER = './test_data/databases/' if not os.path.exists(config.DATA_FOLDER): os.makedirs(config.DATA_FOLDER) setup_logging(os.path.join(config.DATA_FOLDER, 'debug.log'), verbose=args.verbose) exchange_manager = exchanges.MultiExchangeManager([ exchanges.CoinMarketCapAPI(config.TOKEN_SYMBOL), exchanges.LiveCoinWatchAPI('ETH'), exchanges.LiveCoinWatchAPI('BTC'), exchanges.IDEXAPI(config.TOKEN_SYMBOL), exchanges.MercatoxAPI(config.TOKEN_SYMBOL), exchanges.UniswapAPI(config.TOKEN_SYMBOL), # 3/13/20 removed 0xChange. Will re-enable in the future. # exchanges.ZxchangeAPI(config.TOKEN_SYMBOL), # 2/12/20 removed coinexchange. homepage says closed. # exchanges.CoinExchangeAPI(config.TOKEN_SYMBOL), # 2/12/20 removed enclaves. blocks all usa traffic. # exchanges.EnclavesAPI(config.TOKEN_SYMBOL), # 2/12/20 removed ethex, they might be out of business. homepage says check later. # exchanges.EthexAPI(config.TOKEN_SYMBOL), # 2/12/20 removed forkdelta. need a new api since livecoinwatch stopped tracking it. # exchanges.ForkDeltaAPI(config.TOKEN_SYMBOL), # exchanges.HotbitAPI(config.TOKEN_SYMBOL), # 2/12/20 removed merklex. seems to have rebranded to nitrade. # exchanges.MerkleXAPI(config.TOKEN_SYMBOL), ]) token = MineableTokenInfo(config.TOKEN_ETH_ADDRESS) storage = Storage(config.DATA_FOLDER) if args.self_test: client = MockClient() apis = APIWrapper(client, storage, exchange_manager, token, start_time) all_self_tests.run_all() elif args.command_test: client = MockClient() apis = APIWrapper(client, storage, exchange_manager, token, start_time) try: asyncio.get_event_loop().run_until_complete(command_test()) except (SystemExit, KeyboardInterrupt): return elif args.speed_test: client = MockClient() apis = APIWrapper(client, storage, exchange_manager, token, start_time) speed_test() elif args.fuzz_test: client = MockClient() apis = APIWrapper(client, storage, exchange_manager, token, start_time) try: all_self_tests.run_command_fuzzer() except (SystemExit, KeyboardInterrupt): return else: logging.info('Starting {} version {}'.format(_PROGRAM_NAME, _VERSION)) logging.debug('discord.py version {}'.format(discord.__version__)) while True: client = discord.Client() apis = APIWrapper(client, storage, exchange_manager, token, start_time) configure_discord_client() try: asyncio.get_event_loop().run_until_complete( keep_running(client, TOKEN)) except (SystemExit, KeyboardInterrupt): raise except: logging.exception('Unexpected error from Discord... retrying') time.sleep(10) # wait a little time to prevent cpu spins try: asyncio.get_event_loop().run_until_complete(client.close()) asyncio.get_event_loop().run_until_complete( client.logout()) except: pass