tx_api: support blockbook, allow url-less operation

Bitcoin Testnet backends were removed.
This broke our tests that work purely on local data but nevertheless
need to know backend URLs. Because the design is less than ideal.

Here, we do a little cleanup:
* blockbook URLs are respected
* Dogecoin is now supported by our blockbook backend so we don't need
  a special tx-api implementation
* it's possible to instantiate a TxApi that is backed by the cache,
  without a known URL
* relevant tests now make use of this feature
pull/25/head
matejcik 6 years ago
parent 85a32d01b9
commit 19a0f4cc7b

@ -17,7 +17,7 @@
import os.path
import json
from .tx_api import TxApiInsight, TxApiBlockCypher
from .tx_api import TxApiInsight
COINS_JSON = os.path.join(os.path.dirname(__file__), 'coins.json')
@ -35,11 +35,11 @@ def _load_coins_json():
def _insight_for_coin(coin):
if not coin['bitcore']:
url = next(iter(coin['blockbook'] + coin['bitcore']), None)
if not url:
return None
zcash = coin['coin_name'].lower().startswith('zcash')
network = 'insight_{}'.format(coin['coin_name'].lower().replace(' ', '_'))
url = coin['bitcore'][0] + '/api/'
return TxApiInsight(network=network, url=url, zcash=zcash)
@ -54,7 +54,4 @@ except Exception as e:
slip44 = {name: coin['slip44'] for name, coin in by_name.items()}
tx_api = {name: _insight_for_coin(coin)
for name, coin in by_name.items()
if coin["bitcore"]}
# fixup for Dogecoin
tx_api['Dogecoin'] = TxApiBlockCypher(network='blockcypher_dogecoin', url='https://api.blockcypher.com/v1/doge/main/')
if coin["blockbook"] or coin["bitcore"]}

@ -20,12 +20,12 @@ import pytest
from .common import TrezorTest
from .conftest import TREZOR_VERSION
from trezorlib import coins
from trezorlib import messages as proto
from trezorlib.client import CallException
from trezorlib.tools import parse_path
from trezorlib.tx_api import TxApiInsight
TxApiTestnet = coins.tx_api['Testnet']
TxApiTestnet = TxApiInsight("insight_testnet")
TXHASH_157041 = unhexlify('1570416eb4302cf52979afd5e6909e37d8fdd874301f7cc87e547e509cb1caa6')

@ -21,12 +21,12 @@ from ..support.ckd_public import deserialize
from .conftest import TREZOR_VERSION
from .common import TrezorTest
from trezorlib import coins
from trezorlib import messages as proto
from trezorlib.client import CallException
from trezorlib.tools import parse_path
from trezorlib.tx_api import TxApiInsight
TxApiTestnet = coins.tx_api["Testnet"]
TxApiTestnet = TxApiInsight("insight_testnet")
class TestMsgSigntxSegwit(TrezorTest):

@ -18,11 +18,11 @@ from binascii import hexlify, unhexlify
from .common import TrezorTest
from ..support.ckd_public import deserialize
from trezorlib import coins
from trezorlib import messages as proto
from trezorlib.tools import parse_path
from trezorlib.tx_api import TxApiInsight
TxApiTestnet = coins.tx_api['Testnet']
TxApiTestnet = TxApiInsight("insight_testnet")
class TestMsgSigntxSegwitNative(TrezorTest):

@ -19,15 +19,17 @@ from binascii import hexlify, unhexlify
from .common import TrezorTest
from ..support import ckd_public as bip32
from trezorlib import messages as proto
from trezorlib.coins import tx_api
from trezorlib.tools import parse_path
from trezorlib.tx_api import TxApiInsight
TxApiTestnet = TxApiInsight("insight_testnet")
class TestMultisigChange(TrezorTest):
def setup_method(self, method):
super(TestMultisigChange, self).setup_method(method)
self.client.set_tx_api(tx_api['Testnet'])
self.client.set_tx_api(TxApiTestnet)
node_ext1 = bip32.deserialize('tpubDADHV9u9Y6gkggintTdMjJE3be58zKNLhpxBQyuEM6Pwx3sN9JVLmMCMN4DNVwL9AKec27z5TaWcWuHzMXiGAtcra5DjwWbvppGX4gaEGVN')
# m/1 => 02c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e

@ -20,7 +20,7 @@ from trezorlib import coins
from trezorlib import tx_api
TxApiBitcoin = coins.tx_api['Bitcoin']
TxApiTestnet = coins.tx_api['Testnet']
TxApiTestnet = tx_api.TxApiInsight("insight_testnet")
tests_dir = os.path.dirname(os.path.abspath(__file__))

@ -25,10 +25,9 @@ cache_dir = None
class TxApi(object):
def __init__(self, network, url):
def __init__(self, network, url=None):
self.network = network
self.url = url
self.pushtx_url = url
def get_url(self, resource, resourceid):
url = '%s%s/%s' % (self.url, resource, resourceid)
@ -44,6 +43,9 @@ class TxApi(object):
except:
pass
if not self.url:
raise RuntimeError("No URL specified and tx not in cache")
try:
url = self.get_url(resource, resourceid)
r = requests.get(url, headers={'User-agent': 'Mozilla/5.0'})
@ -63,10 +65,11 @@ class TxApi(object):
class TxApiInsight(TxApi):
def __init__(self, network, url, zcash=None):
super(TxApiInsight, self).__init__(network, url)
def __init__(self, network, url=None, zcash=None):
super().__init__(network, url)
self.zcash = zcash
self.pushtx_url = url.replace('/api/', '/tx/send')
if url:
self.pushtx_url = url.replace('/api/', '/tx/send')
def get_tx(self, txhash):
@ -112,38 +115,3 @@ class TxApiInsight(TxApi):
t.extra_data = raw[-extra_data_len:]
return t
class TxApiBlockCypher(TxApi):
def __init__(self, network, url, zcash=None):
super(TxApiBlockCypher, self).__init__(network, url)
self.pushtx_url = url.replace('//api.', '//live.').replace('/v1/', '/').replace('/main/', '/pushtx/')
def get_tx(self, txhash):
data = self.fetch_json('txs', txhash)
t = proto.TransactionType()
t.version = data['ver']
t.lock_time = data.get('lock_time', 0)
for vin in data['inputs']:
i = t._add_inputs()
if 'prev_hash' not in vin:
i.prev_hash = b"\0" * 32
i.prev_index = 0xffffffff # signed int -1
i.script_sig = binascii.unhexlify(vin['script'])
i.sequence = vin['sequence']
else:
i.prev_hash = binascii.unhexlify(vin['prev_hash'])
i.prev_index = vin['output_index']
i.script_sig = binascii.unhexlify(vin['script'])
i.sequence = vin['sequence']
for vout in data['outputs']:
o = t._add_bin_outputs()
o.amount = int(str(vout['value']), 10)
o.script_pubkey = binascii.unhexlify(vout['script'])
return t

Loading…
Cancel
Save