Exemple #1
0
 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)
Exemple #3
0
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