prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Bitcoin legacy xpub with too many used address may fail to query balances after restart
  ## Problem Definition
  
  If a user adds a legacy xpub that generates too many used addresses rotki will properly add the xpub and all its addresses. But then after a restart it will fail to query all balances again.
  
  Error is:
  
  ```
  Error at querying blockchain balances: bitcoin external API request for balances failed due to https://blockchain.info/multiaddr?active=XXXXXX
  ```
  
  The failure is due to attempting to query all addresses from blockchain.info using the multiaddr endpoint which seems to have a non-documented limit.
  
  blockchain.info errors with a 502 if too many bitcoin addresses are sent.
  
  ## Task
  
  Fix it by experimenting and figuring out a safe limit.
  Then apply that limit where we query for multiple legacy bitcoin addresses.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `rotkehlchen/chain/bitcoin/__init__.py`
  Content:
  ```
  1 from typing import Dict, List, Tuple
  2 
  3 import requests
  4 
  5 from rotkehlchen.errors import RemoteError, UnableToDecryptRemoteData
  6 from rotkehlchen.fval import FVal
  7 from rotkehlchen.typing import BTCAddress
  8 from rotkehlchen.utils.misc import satoshis_to_btc
  9 from rotkehlchen.utils.network import request_get_dict
  10 
  11 
  12 def _have_bc1_accounts(accounts: List[BTCAddress]) -> bool:
  13     return any(account.lower()[0:3] == 'bc1' for account in accounts)
  14 
  15 
  16 def get_bitcoin_addresses_balances(accounts: List[BTCAddress]) -> Dict[BTCAddress, FVal]:
  17     """Queries blockchain.info or blockstream for the balances of accounts
  18 
  19     May raise:
  20     - RemotError if there is a problem querying blockchain.info or blockstream
  21     """
  22     source = 'blockchain.info'
  23     balances: Dict[BTCAddress, FVal] = {}
  24     try:
  25         if _have_bc1_accounts(accounts):
  26             # if 1 account is bech32 we have to query blockstream. blockchaininfo won't work
  27             source = 'blockstream'
  28             balances = {}
  29             for account in accounts:
  30                 url = f'https://blockstream.info/api/address/{account}'
  31                 response_data = request_get_dict(url=url, handle_429=True, backoff_in_seconds=4)
  32                 stats = response_data['chain_stats']
  33                 balance = int(stats['funded_txo_sum']) - int(stats['spent_txo_sum'])
  34                 balances[account] = satoshis_to_btc(balance)
  35         else:
  36             params = '|'.join(accounts)
  37             btc_resp = request_get_dict(
  38                 url=f'https://blockchain.info/multiaddr?active={params}',
  39                 handle_429=True,
  40                 # If we get a 429 then their docs suggest 10 seconds
  41                 # https://blockchain.info/q
  42                 backoff_in_seconds=10,
  43             )
  44             for entry in btc_resp['addresses']:
  45                 balances[entry['address']] = satoshis_to_btc(FVal(entry['final_balance']))
  46     except (
  47             requests.exceptions.RequestException,
  48             UnableToDecryptRemoteData,
  49             requests.exceptions.Timeout,
  50     ) as e:
  51         raise RemoteError(f'bitcoin external API request for balances failed due to {str(e)}') from e  # noqa: E501
  52     except KeyError as e:
  53         raise RemoteError(
  54             f'Malformed response when querying bitcoin blockchain via {source}.'
  55             f'Did not find key {e}',
  56         ) from e
  57 
  58     return balances
  59 
  60 
  61 def _check_blockstream_for_transactions(
  62         accounts: List[BTCAddress],
  63 ) -> Dict[BTCAddress, Tuple[bool, FVal]]:
  64     """May raise connection errors or KeyError"""
  65     have_transactions = {}
  66     for account in accounts:
  67         url = f'https://blockstream.info/api/address/{account}'
  68         response_data = request_get_dict(url=url, handle_429=True, backoff_in_seconds=4)
  69         stats = response_data['chain_stats']
  70         balance = satoshis_to_btc(int(stats['funded_txo_sum']) - int(stats['spent_txo_sum']))
  71         have_txs = stats['tx_count'] != 0
  72         have_transactions[account] = (have_txs, balance)
  73 
  74     return have_transactions
  75 
  76 
  77 def _check_blockchaininfo_for_transactions(
  78         accounts: List[BTCAddress],
  79 ) -> Dict[BTCAddress, Tuple[bool, FVal]]:
  80     """May raise RemotError or KeyError"""
  81     have_transactions = {}
  82     params = '|'.join(accounts)
  83     btc_resp = request_get_dict(
  84         url=f'https://blockchain.info/multiaddr?active={params}',
  85         handle_429=True,
  86         # If we get a 429 then their docs suggest 10 seconds
  87         # https://blockchain.infoq/
  88         backoff_in_seconds=15,
  89     )
  90     for entry in btc_resp['addresses']:
  91         balance = satoshis_to_btc(entry['final_balance'])
  92         have_transactions[entry['address']] = (entry['n_tx'] != 0, balance)
  93 
  94     return have_transactions
  95 
  96 
  97 def have_bitcoin_transactions(accounts: List[BTCAddress]) -> Dict[BTCAddress, Tuple[bool, FVal]]:
  98     """
  99     Takes a list of addresses and returns a mapping of which addresses have had transactions
  100     and also their current balance
  101 
  102     May raise:
  103     - RemoteError if any of the queried websites fail to be queried
  104     """
  105     try:
  106         if _have_bc1_accounts(accounts):
  107             source = 'blockstream'
  108             have_transactions = _check_blockstream_for_transactions(accounts)
  109         else:
  110             source = 'blockchain.info'
  111             have_transactions = _check_blockchaininfo_for_transactions(accounts)
  112     except (
  113             requests.exceptions.RequestException,
  114             UnableToDecryptRemoteData,
  115             requests.exceptions.Timeout,
  116     ) as e:
  117         raise RemoteError(f'bitcoin external API request for transactions failed due to {str(e)}') from e  # noqa: E501
  118     except KeyError as e:
  119         raise RemoteError(
  120             f'Malformed response when querying bitcoin blockchain via {source}.'
  121             f'Did not find key {str(e)}',
  122         ) from e
  123 
  124     return have_transactions
  125
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/rotkehlchen/chain/bitcoin/__init__.py b/rotkehlchen/chain/bitcoin/__init__.py
  --- a/rotkehlchen/chain/bitcoin/__init__.py
  +++ b/rotkehlchen/chain/bitcoin/__init__.py
  @@ -33,16 +33,20 @@
                   balance = int(stats['funded_txo_sum']) - int(stats['spent_txo_sum'])
                   balances[account] = satoshis_to_btc(balance)
           else:
  -            params = '|'.join(accounts)
  -            btc_resp = request_get_dict(
  -                url=f'https://blockchain.info/multiaddr?active={params}',
  -                handle_429=True,
  -                # If we get a 429 then their docs suggest 10 seconds
  -                # https://blockchain.info/q
  -                backoff_in_seconds=10,
  -            )
  -            for entry in btc_resp['addresses']:
  -                balances[entry['address']] = satoshis_to_btc(FVal(entry['final_balance']))
  +            # split the list of accounts into sublists of 80 addresses per list to overcome:
  +            # https://github.com/rotki/rotki/issues/3037
  +            accounts_chunks = [accounts[x:x + 80] for x in range(0, len(accounts), 80)]
  +            for accounts_chunk in accounts_chunks:
  +                params = '|'.join(accounts_chunk)
  +                btc_resp = request_get_dict(
  +                    url=f'https://blockchain.info/multiaddr?active={params}',
  +                    handle_429=True,
  +                    # If we get a 429 then their docs suggest 10 seconds
  +                    # https://blockchain.info/q
  +                    backoff_in_seconds=10,
  +                )
  +                for entry in btc_resp['addresses']:
  +                    balances[entry['address']] = satoshis_to_btc(FVal(entry['final_balance']))
       except (
               requests.exceptions.RequestException,
               UnableToDecryptRemoteData,
  
verification_info: {"golden_diff": "diff --git a/rotkehlchen/chain/bitcoin/__init__.py b/rotkehlchen/chain/bitcoin/__init__.py\n--- a/rotkehlchen/chain/bitcoin/__init__.py\n+++ b/rotkehlchen/chain/bitcoin/__init__.py\n@@ -33,16 +33,20 @@\n                 balance = int(stats['funded_txo_sum']) - int(stats['spent_txo_sum'])\n                 balances[account] = satoshis_to_btc(balance)\n         else:\n-            params = '|'.join(accounts)\n-            btc_resp = request_get_dict(\n-                url=f'https://blockchain.info/multiaddr?active={params}',\n-                handle_429=True,\n-                # If we get a 429 then their docs suggest 10 seconds\n-                # https://blockchain.info/q\n-                backoff_in_seconds=10,\n-            )\n-            for entry in btc_resp['addresses']:\n-                balances[entry['address']] = satoshis_to_btc(FVal(entry['final_balance']))\n+            # split the list of accounts into sublists of 80 addresses per list to overcome:\n+            # https://github.com/rotki/rotki/issues/3037\n+            accounts_chunks = [accounts[x:x + 80] for x in range(0, len(accounts), 80)]\n+            for accounts_chunk in accounts_chunks:\n+                params = '|'.join(accounts_chunk)\n+                btc_resp = request_get_dict(\n+                    url=f'https://blockchain.info/multiaddr?active={params}',\n+                    handle_429=True,\n+                    # If we get a 429 then their docs suggest 10 seconds\n+                    # https://blockchain.info/q\n+                    backoff_in_seconds=10,\n+                )\n+                for entry in btc_resp['addresses']:\n+                    balances[entry['address']] = satoshis_to_btc(FVal(entry['final_balance']))\n     except (\n             requests.exceptions.RequestException,\n             UnableToDecryptRemoteData,\n", "issue": "Bitcoin legacy xpub with too many used address may fail to query balances after restart\n## Problem Definition\r\n\r\nIf a user adds a legacy xpub that generates too many used addresses rotki will properly add the xpub and all its addresses. But then after a restart it will fail to query all balances again.\r\n\r\nError is:\r\n\r\n```\r\nError at querying blockchain balances: bitcoin external API request for balances failed due to https://blockchain.info/multiaddr?active=XXXXXX\r\n```\r\n\r\nThe failure is due to attempting to query all addresses from blockchain.info using the multiaddr endpoint which seems to have a non-documented limit.\r\n\r\nblockchain.info errors with a 502 if too many bitcoin addresses are sent.\r\n\r\n## Task\r\n\r\nFix it by experimenting and figuring out a safe limit.\r\nThen apply that limit where we query for multiple legacy bitcoin addresses.\n", "before_files": [{"content": "from typing import Dict, List, Tuple\n\nimport requests\n\nfrom rotkehlchen.errors import RemoteError, UnableToDecryptRemoteData\nfrom rotkehlchen.fval import FVal\nfrom rotkehlchen.typing import BTCAddress\nfrom rotkehlchen.utils.misc import satoshis_to_btc\nfrom rotkehlchen.utils.network import request_get_dict\n\n\ndef _have_bc1_accounts(accounts: List[BTCAddress]) -> bool:\n    return any(account.lower()[0:3] == 'bc1' for account in accounts)\n\n\ndef get_bitcoin_addresses_balances(accounts: List[BTCAddress]) -> Dict[BTCAddress, FVal]:\n    \"\"\"Queries blockchain.info or blockstream for the balances of accounts\n\n    May raise:\n    - RemotError if there is a problem querying blockchain.info or blockstream\n    \"\"\"\n    source = 'blockchain.info'\n    balances: Dict[BTCAddress, FVal] = {}\n    try:\n        if _have_bc1_accounts(accounts):\n            # if 1 account is bech32 we have to query blockstream. blockchaininfo won't work\n            source = 'blockstream'\n            balances = {}\n            for account in accounts:\n                url = f'https://blockstream.info/api/address/{account}'\n                response_data = request_get_dict(url=url, handle_429=True, backoff_in_seconds=4)\n                stats = response_data['chain_stats']\n                balance = int(stats['funded_txo_sum']) - int(stats['spent_txo_sum'])\n                balances[account] = satoshis_to_btc(balance)\n        else:\n            params = '|'.join(accounts)\n            btc_resp = request_get_dict(\n                url=f'https://blockchain.info/multiaddr?active={params}',\n                handle_429=True,\n                # If we get a 429 then their docs suggest 10 seconds\n                # https://blockchain.info/q\n                backoff_in_seconds=10,\n            )\n            for entry in btc_resp['addresses']:\n                balances[entry['address']] = satoshis_to_btc(FVal(entry['final_balance']))\n    except (\n            requests.exceptions.RequestException,\n            UnableToDecryptRemoteData,\n            requests.exceptions.Timeout,\n    ) as e:\n        raise RemoteError(f'bitcoin external API request for balances failed due to {str(e)}') from e  # noqa: E501\n    except KeyError as e:\n        raise RemoteError(\n            f'Malformed response when querying bitcoin blockchain via {source}.'\n            f'Did not find key {e}',\n        ) from e\n\n    return balances\n\n\ndef _check_blockstream_for_transactions(\n        accounts: List[BTCAddress],\n) -> Dict[BTCAddress, Tuple[bool, FVal]]:\n    \"\"\"May raise connection errors or KeyError\"\"\"\n    have_transactions = {}\n    for account in accounts:\n        url = f'https://blockstream.info/api/address/{account}'\n        response_data = request_get_dict(url=url, handle_429=True, backoff_in_seconds=4)\n        stats = response_data['chain_stats']\n        balance = satoshis_to_btc(int(stats['funded_txo_sum']) - int(stats['spent_txo_sum']))\n        have_txs = stats['tx_count'] != 0\n        have_transactions[account] = (have_txs, balance)\n\n    return have_transactions\n\n\ndef _check_blockchaininfo_for_transactions(\n        accounts: List[BTCAddress],\n) -> Dict[BTCAddress, Tuple[bool, FVal]]:\n    \"\"\"May raise RemotError or KeyError\"\"\"\n    have_transactions = {}\n    params = '|'.join(accounts)\n    btc_resp = request_get_dict(\n        url=f'https://blockchain.info/multiaddr?active={params}',\n        handle_429=True,\n        # If we get a 429 then their docs suggest 10 seconds\n        # https://blockchain.infoq/\n        backoff_in_seconds=15,\n    )\n    for entry in btc_resp['addresses']:\n        balance = satoshis_to_btc(entry['final_balance'])\n        have_transactions[entry['address']] = (entry['n_tx'] != 0, balance)\n\n    return have_transactions\n\n\ndef have_bitcoin_transactions(accounts: List[BTCAddress]) -> Dict[BTCAddress, Tuple[bool, FVal]]:\n    \"\"\"\n    Takes a list of addresses and returns a mapping of which addresses have had transactions\n    and also their current balance\n\n    May raise:\n    - RemoteError if any of the queried websites fail to be queried\n    \"\"\"\n    try:\n        if _have_bc1_accounts(accounts):\n            source = 'blockstream'\n            have_transactions = _check_blockstream_for_transactions(accounts)\n        else:\n            source = 'blockchain.info'\n            have_transactions = _check_blockchaininfo_for_transactions(accounts)\n    except (\n            requests.exceptions.RequestException,\n            UnableToDecryptRemoteData,\n            requests.exceptions.Timeout,\n    ) as e:\n        raise RemoteError(f'bitcoin external API request for transactions failed due to {str(e)}') from e  # noqa: E501\n    except KeyError as e:\n        raise RemoteError(\n            f'Malformed response when querying bitcoin blockchain via {source}.'\n            f'Did not find key {str(e)}',\n        ) from e\n\n    return have_transactions\n", "path": "rotkehlchen/chain/bitcoin/__init__.py"}], "after_files": [{"content": "from typing import Dict, List, Tuple\n\nimport requests\n\nfrom rotkehlchen.errors import RemoteError, UnableToDecryptRemoteData\nfrom rotkehlchen.fval import FVal\nfrom rotkehlchen.typing import BTCAddress\nfrom rotkehlchen.utils.misc import satoshis_to_btc\nfrom rotkehlchen.utils.network import request_get_dict\n\n\ndef _have_bc1_accounts(accounts: List[BTCAddress]) -> bool:\n    return any(account.lower()[0:3] == 'bc1' for account in accounts)\n\n\ndef get_bitcoin_addresses_balances(accounts: List[BTCAddress]) -> Dict[BTCAddress, FVal]:\n    \"\"\"Queries blockchain.info or blockstream for the balances of accounts\n\n    May raise:\n    - RemotError if there is a problem querying blockchain.info or blockstream\n    \"\"\"\n    source = 'blockchain.info'\n    balances: Dict[BTCAddress, FVal] = {}\n    try:\n        if _have_bc1_accounts(accounts):\n            # if 1 account is bech32 we have to query blockstream. blockchaininfo won't work\n            source = 'blockstream'\n            balances = {}\n            for account in accounts:\n                url = f'https://blockstream.info/api/address/{account}'\n                response_data = request_get_dict(url=url, handle_429=True, backoff_in_seconds=4)\n                stats = response_data['chain_stats']\n                balance = int(stats['funded_txo_sum']) - int(stats['spent_txo_sum'])\n                balances[account] = satoshis_to_btc(balance)\n        else:\n            # split the list of accounts into sublists of 80 addresses per list to overcome:\n            # https://github.com/rotki/rotki/issues/3037\n            accounts_chunks = [accounts[x:x + 80] for x in range(0, len(accounts), 80)]\n            for accounts_chunk in accounts_chunks:\n                params = '|'.join(accounts_chunk)\n                btc_resp = request_get_dict(\n                    url=f'https://blockchain.info/multiaddr?active={params}',\n                    handle_429=True,\n                    # If we get a 429 then their docs suggest 10 seconds\n                    # https://blockchain.info/q\n                    backoff_in_seconds=10,\n                )\n                for entry in btc_resp['addresses']:\n                    balances[entry['address']] = satoshis_to_btc(FVal(entry['final_balance']))\n    except (\n            requests.exceptions.RequestException,\n            UnableToDecryptRemoteData,\n            requests.exceptions.Timeout,\n    ) as e:\n        raise RemoteError(f'bitcoin external API request for balances failed due to {str(e)}') from e  # noqa: E501\n    except KeyError as e:\n        raise RemoteError(\n            f'Malformed response when querying bitcoin blockchain via {source}.'\n            f'Did not find key {e}',\n        ) from e\n\n    return balances\n\n\ndef _check_blockstream_for_transactions(\n        accounts: List[BTCAddress],\n) -> Dict[BTCAddress, Tuple[bool, FVal]]:\n    \"\"\"May raise connection errors or KeyError\"\"\"\n    have_transactions = {}\n    for account in accounts:\n        url = f'https://blockstream.info/api/address/{account}'\n        response_data = request_get_dict(url=url, handle_429=True, backoff_in_seconds=4)\n        stats = response_data['chain_stats']\n        balance = satoshis_to_btc(int(stats['funded_txo_sum']) - int(stats['spent_txo_sum']))\n        have_txs = stats['tx_count'] != 0\n        have_transactions[account] = (have_txs, balance)\n\n    return have_transactions\n\n\ndef _check_blockchaininfo_for_transactions(\n        accounts: List[BTCAddress],\n) -> Dict[BTCAddress, Tuple[bool, FVal]]:\n    \"\"\"May raise RemotError or KeyError\"\"\"\n    have_transactions = {}\n    params = '|'.join(accounts)\n    btc_resp = request_get_dict(\n        url=f'https://blockchain.info/multiaddr?active={params}',\n        handle_429=True,\n        # If we get a 429 then their docs suggest 10 seconds\n        # https://blockchain.infoq/\n        backoff_in_seconds=15,\n    )\n    for entry in btc_resp['addresses']:\n        balance = satoshis_to_btc(entry['final_balance'])\n        have_transactions[entry['address']] = (entry['n_tx'] != 0, balance)\n\n    return have_transactions\n\n\ndef have_bitcoin_transactions(accounts: List[BTCAddress]) -> Dict[BTCAddress, Tuple[bool, FVal]]:\n    \"\"\"\n    Takes a list of addresses and returns a mapping of which addresses have had transactions\n    and also their current balance\n\n    May raise:\n    - RemoteError if any of the queried websites fail to be queried\n    \"\"\"\n    try:\n        if _have_bc1_accounts(accounts):\n            source = 'blockstream'\n            have_transactions = _check_blockstream_for_transactions(accounts)\n        else:\n            source = 'blockchain.info'\n            have_transactions = _check_blockchaininfo_for_transactions(accounts)\n    except (\n            requests.exceptions.RequestException,\n            UnableToDecryptRemoteData,\n            requests.exceptions.Timeout,\n    ) as e:\n        raise RemoteError(f'bitcoin external API request for transactions failed due to {str(e)}') from e  # noqa: E501\n    except KeyError as e:\n        raise RemoteError(\n            f'Malformed response when querying bitcoin blockchain via {source}.'\n            f'Did not find key {str(e)}',\n        ) from e\n\n    return have_transactions\n", "path": "rotkehlchen/chain/bitcoin/__init__.py"}]}