pybitcash/bitcash

ConnectionError: All APIs are unreachable

Closed this issue · 6 comments

A program I develop based on BitCash worked without issues since the last days.
I started to get a ConnectionError every time I tried to broadcast a tx: "Transaction broadcast failed or unspends were already used". Now, all APIs are unreachable. I don't use any custom API, does BitCash use rest1.biggestfan.net as default? Is it giving troubles to anyone else?

EDIT: Despite the "All APIs are unreachable" error message, the script is working and txs are being broadcasted.

A program I develop based on BitCash worked without issues since the last days.

I started to get a ConnectionError every time I tried to broadcast a tx: "Transaction broadcast failed or unspends were already used". Now, all APIs are unreachable. I don't use any custom API, does BitCash use rest1.biggestfan.net as default? Is it giving troubles to anyone else?

EDIT: Despite the "All APIs are unreachable" error message, the script is working and txs are being broadcasted.

Yes I'm having the same issue. Will reach out to BiggestFan.

Just to leave some more info, reading the docs it seems that BitCash uses BitPay API. Browsing https://bitpay.com/insight/#/ALL/mainnet/home I found that a 429 error is raised for BCH and many other networks:
Error 429: Http failure response for https://api.bitcore.io/api/BCH/mainnet/block?limit=5: 429 Too Many Requests

Nvm, I've been reading the Python code and it seems that BitCash uses https://rest.bch.actorforth.org/v2/ as first option by default. I tried sending a raw transaction using their web interface and it worked. The raw tx was constructed from BitCash, so it's the broadcasting the failing point. I always broadcast the tx this way:
NetworkAPI.broadcast_tx(my_tx)

Just to leave some more info, reading the docs it seems that BitCash uses BitPay API. Browsing https://bitpay.com/insight/#/ALL/mainnet/home I found that a 429 error is raised for BCH and many other networks:

Error 429: Http failure response for https://api.bitcore.io/api/BCH/mainnet/block?limit=5: 429 Too Many Requests

Nvm, I've been reading the Python code and it seems that BitCash uses https://rest.bch.actorforth.org/v2/ as first option by default. I tried sending a raw transaction using their web interface and it worked. The raw tx was constructed from BitCash, so it's the broadcasting the failing point. I always broadcast the tx this way:

NetworkAPI.broadcast_tx(my_tx)

BitPay is used to calculate the fiat rate.

Yes I tried sending transactions through the web interface directly and it worked. It also works if I query the UTXO, wait 1 second then broadcast the transaction.

I will try to write a script that reproduces the issue so I can investigate this with BiggestFan

I'm not sure if this is related or not, but I am getting the same error when trying to get_transactions().

Code

#!.venv/bin/python

# .venv/bin/pip install coincurve bitcash qrcode[pil]

import os
import qrcode
import bitcash
from bitcash import Key, PrivateKeyTestnet

class Wallet(object):
    BCH_DIR = os.path.join(os.path.dirname(__file__), '.bch')
    def __init__(self, name, net='mainnet'):
        self.name = name
        self.net = net
        bch_dir = f'{self.BCH_DIR}' if net == 'mainnet' else f'{self.BCH_DIR}{self.net}'
        if not os.path.isdir(bch_dir):
            os.mkdir(bch_dir)
        key_dir = os.path.join(bch_dir, name)
        if not os.path.isdir(key_dir):
            os.mkdir(key_dir)
        self._key_path = os.path.join(key_dir, 'pkey')
        if not os.path.exists(self._key_path):
            with open(self._key_path, 'w+') as pkey:
                print(f'creating wallet {name} private key on net: {net}')
                key = Key() if net != 'test' else PrivateKeyTestnet(network=net)
                pkey.write(str(key.to_pem().decode()))
        with open(self._key_path, 'r') as pkey:
            K = Key if net != 'test' else PrivateKeyTestnet
            self._key = K.from_pem(pkey.read().encode('utf-8')) 
        self._qr_path = os.path.join(key_dir, 'address_qr.png')
        if not os.path.exists(self._qr_path):
            with open(self._qr_path, 'w+') as pkey:
                print(f'creating qr image for {name} private key on net: {net}')
                qr = qrcode.QRCode(
                    version=1,
                    error_correction=qrcode.constants.ERROR_CORRECT_L,
                    box_size=10,
                    border=4,
                )
                qr.add_data(key.address)
                qr.make(fit=True)
                img = qr.make_image(fill_color="black", back_color="white")
                img.save(self._qr_path, format=img.format)

    @property
    def key_path(self):
        return self._key_path
    @property
    def key(self):
        return self._key
    @property
    def address(self):
        return self._key.address
    @property
    def balance(self, currency='bch'):
        return self._key.balance_as(currency)
    @property
    def transactions(self):
        return self._key.get_transactions()
    @property
    def qr_path(self):
        return self._qr_path

    
if __name__ == '__main__':
    wa = Wallet('a', net='test')
    wb = Wallet('b', net='test')
    for w in [wa, wb]:
        print(f'wallet {w.name}: {w.address} -> {w.balance}')
    for w in [wa, wb]:
        print(f'keytype {w.name}: {type(w.key)}')
    for w in [wa, wb]:
        print(f'transactions {w.name}: {w.transactions}')

Output

$ ./bch-ping-pong.py 
wallet a: bchtest:qqgsu0pcsyp3c23yxn5ny56fpa6yzv33nswsnn0zz9 -> 0
wallet b: bchtest:qp2zw5e32k2cc5jzkgp6e3y625nh89qm3urwc6vxaj -> 0
keytype a: <class 'bitcash.wallet.PrivateKeyTestnet'>
keytype b: <class 'bitcash.wallet.PrivateKeyTestnet'>
Traceback (most recent call last):
  File "./bch-ping-pong.py", line 71, in <module>
    print(f'transactions {w.name}: {w.transactions}')
  File "./bch-ping-pong.py", line 57, in transactions
    return self._key.get_transactions()
  File "/Users/will/williamcharltonengineering/bch-ping-pong/.venv/lib/python3.8/site-packages/bitcash/wallet.py", line 238, in get_transactions
    self.transactions[:] = NetworkAPI.get_transactions(
  File "/Users/will/williamcharltonengineering/bch-ping-pong/.venv/lib/python3.8/site-packages/bitcash/network/services.py", line 112, in get_transactions
    raise ConnectionError("All APIs are unreachable.")  # pragma: no cover
ConnectionError: All APIs are unreachable.

If I switch to net='mainnet' in the Wallet constructor then it works.

@willcharlton could you submit a minimal reproducible example?

With that I would be able to investigate this issue further.

This should be fixed.