Skip to content

Commit

Permalink
Remove bitgo and bitaps providers for testnet, reenable blockcypher
Browse files Browse the repository at this point in the history
  • Loading branch information
Cryp Toon committed May 14, 2024
1 parent 4c3ed2a commit 1393e97
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 109 deletions.
33 changes: 11 additions & 22 deletions bitcoinlib/data/providers.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,6 @@
"denominator": 1,
"network_overrides": null
},
"bitgo.testnet": {
"provider": "bitgo",
"network": "testnet",
"client_class": "BitGoClient",
"provider_coin_id": "",
"url": "https://test.bitgo.com/api/v1/",
"api_key": "",
"priority": 10,
"denominator": 1,
"network_overrides": null
},
"blockcypher.litecoin": {
"provider": "blockcypher",
"network": "litecoin",
Expand Down Expand Up @@ -142,17 +131,6 @@
"denominator": 100000000,
"network_overrides": null
},
"bitaps.testnet": {
"provider": "bitaps",
"network": "testnet",
"client_class": "BitapsClient",
"provider_coin_id": "",
"url": "https://api.bitaps.com/btc/testnet/v1/",
"api_key": "",
"priority": 10,
"denominator": 100000000,
"network_overrides": null
},
"bitaps.litecoin": {
"provider": "bitaps",
"network": "litecoin",
Expand Down Expand Up @@ -329,6 +307,17 @@
"denominator": 1,
"network_overrides": null
},
"blockcypher.testnet": {
"provider": "blockcypher",
"network": "testnet",
"client_class": "BlockCypher",
"provider_coin_id": "",
"url": "https://api.blockcypher.com/v1/btc/test3/",
"api_key": "",
"priority": 10,
"denominator": 1,
"network_overrides": null
},
"mempool": {
"provider": "mempool",
"network": "bitcoin",
Expand Down
2 changes: 2 additions & 0 deletions bitcoinlib/services/bitaps.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ def gettransactions(self, address, after_txid='', limit=MAX_TRANSACTIONS):
# def estimatefee

def blockcount(self):
if self.network == 'testnet':
raise ClientError('Providers return incorrect blockcount for testnet')
return self.compose_request('block', 'last')['data']['height']

# def mempool(self, txid):
Expand Down
2 changes: 2 additions & 0 deletions bitcoinlib/services/bitgo.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ def estimatefee(self, blocks):
return res['feePerKb']

def blockcount(self):
if self.network == 'testnet':
raise ClientError('Providers return incorrect blockcount for testnet')
return self.compose_request('block', 'latest')['height']

# def mempool
Expand Down
65 changes: 32 additions & 33 deletions bitcoinlib/services/blockcypher.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,39 +56,38 @@ def getbalance(self, addresslist):
balance += float(rec['final_balance'])
return int(balance * self.units)

# Disabled: Invalid results for https://api.blockcypher.com/v1/ltc/main/addrs/LVqLipGhyQ1nWtPPc8Xp3zn6JxcU1Hi8eG?unspentOnly=1&limit=2000
# def getutxos(self, address, after_txid='', limit=MAX_TRANSACTIONS):
# address = self._address_convert(address)
# res = self.compose_request('addrs', address.address, variables={'unspentOnly': 1, 'limit': 2000})
# transactions = []
# if not isinstance(res, list):
# res = [res]
# for a in res:
# txrefs = a.setdefault('txrefs', []) + a.get('unconfirmed_txrefs', [])
# if len(txrefs) > 500:
# _logger.warning("BlockCypher: Large number of transactions for address %s, "
# "Transaction list may be incomplete" % address)
# for tx in txrefs:
# if tx['tx_hash'] == after_txid:
# break
# tdate = None
# if 'confirmed' in tx:
# try:
# tdate = datetime.strptime(tx['confirmed'], "%Y-%m-%dT%H:%M:%SZ")
# except ValueError:
# tdate = datetime.strptime(tx['confirmed'], "%Y-%m-%dT%H:%M:%S.%fZ")
# transactions.append({
# 'address': address.address_orig,
# 'txid': tx['tx_hash'],
# 'confirmations': tx['confirmations'],
# 'output_n': tx['tx_output_n'],
# 'index': 0,
# 'value': int(round(tx['value'] * self.units, 0)),
# 'script': '',
# 'block_height': None,
# 'date': tdate
# })
# return transactions[::-1][:limit]
def getutxos(self, address, after_txid='', limit=MAX_TRANSACTIONS):
address = self._address_convert(address)
res = self.compose_request('addrs', address.address, variables={'unspentOnly': 1, 'limit': 2000})
transactions = []
if not isinstance(res, list):
res = [res]
for a in res:
txrefs = a.setdefault('txrefs', []) + a.get('unconfirmed_txrefs', [])
if len(txrefs) > 500:
_logger.warning("BlockCypher: Large number of transactions for address %s, "
"Transaction list may be incomplete" % address)
for tx in txrefs:
if tx['tx_hash'] == after_txid:
break
tdate = None
if 'confirmed' in tx:
try:
tdate = datetime.strptime(tx['confirmed'], "%Y-%m-%dT%H:%M:%SZ")
except ValueError:
tdate = datetime.strptime(tx['confirmed'], "%Y-%m-%dT%H:%M:%S.%fZ")
transactions.append({
'address': address.address_orig,
'txid': tx['tx_hash'],
'confirmations': tx['confirmations'],
'output_n': tx['tx_output_n'],
'index': 0,
'value': int(round(tx['value'] * self.units, 0)),
'script': '',
'block_height': None,
'date': tdate
})
return transactions[::-1][:limit]

def gettransaction(self, txid):
tx = self.compose_request('txs', txid, variables={'includeHex': 'true'})
Expand Down
104 changes: 50 additions & 54 deletions tests/test_wallets.py
Original file line number Diff line number Diff line change
Expand Up @@ -1408,7 +1408,7 @@ def test_wallet_multisig_info(self):
HDKey(network='bitcoinlib_test')],
network='bitcoinlib_test', cosigner_id=0, db_uri=self.database_uri)
w.utxos_update()
w.info(detail=6)
self.assertIsNone(w.info(detail=6))

def test_wallets_multisig_missing_private_and_cosigner(self):
k0 = 'xprv9s21ZrQH143K459uwGGCU3Wj3v1LFFJ42tgyTsNnr6p2BS6FZ9jQ7fmZMMnqsWSi2BBgpX3hFbR4ode8Jx58ibSNeaBLFQ68Xs3' \
Expand Down Expand Up @@ -1729,18 +1729,16 @@ def test_wallet_offline_create_transaction(self):
del wlt

def test_wallet_scan(self):
# TODO: Fix MySQL scan errors
if self.database_uri.startswith('mysql'):
self.skipTest('TODO: Fix MySQL scan errors')
account_key = 'tpubDCmJWqxWch7LYDhSuE1jEJMbAkbkDm3DotWKZ69oZfNMzuw7U5DwEaTVZHGPzt5j9BJDoxqVkPHt2EpUF66FrZhpfq' \
'ZY6DFj6x61Wwbrg8Q'
wallet = wallet_create_or_open('scan-test', keys=account_key, network='testnet', db_uri=self.database_uri)
wallet.scan(scan_gap_limit=8)
self.assertEqual(len(wallet.keys()), 27)
self.assertEqual(wallet.balance(), 60500000)
self.assertEqual(len(wallet.transactions()), 4)
self.assertEqual(len(wallet.transactions(as_dict=True)), 4)
wallet.scan(scan_gap_limit=1)
self.assertEqual(len(wallet.keys()), 6)
self.assertEqual(wallet.balance(), 60000000)
self.assertEqual(len(wallet.transactions()), 3)
self.assertEqual(len(wallet.transactions(as_dict=True)), 3)

def test_wallet_scan_tx_order_same_block(self):
# Check tx order in same block
address = 'tb1qlh9x3jwhfqspp7u9w6l7zqxpmuvplzaczaele3'
w = wallet_create_or_open('fix-multiple-tx-1-block', keys=address, db_uri=self.database_uri)
Expand Down Expand Up @@ -2012,33 +2010,33 @@ def test_wallet_transaction_sign_with_wif(self):
self.assertIsNone(t.send())
self.assertTrue(t.pushed)

#FIXME
# def test_wallet_transaction_restore_saved_tx(self):
# w = wallet_create_or_open('test_wallet_transaction_restore', network='bitcoinlib_test',
# db_uri=self.database_uri)
# wk = w.get_key()
# if not USE_FASTECDSA:
# self.skipTest("Need fastecdsa module with deterministic txid's to run this test")
# utxos = [{
# 'address': wk.address,
# 'script': '',
# 'confirmations': 10,
# 'output_n': 1,
# 'txid': '9f5d4004c7cc5a31a735bddea6ff517e52f1cd700df208d2c39ddc536670f1fe',
# 'value': 1956783097
# }]
# w.utxos_update(utxos=utxos)
# to = w.get_key_change()
# t = w.sweep(to.address)
# tx_id = t.store()
# wallet_empty('test_wallet_transaction_restore', db_uri=self.database_uri)
# w = wallet_create_or_open('test_wallet_transaction_restore', network='bitcoinlib_test',
# db_uri=self.database_uri)
# w.get_key()
# w.utxos_update(utxos=utxos)
# to = w.get_key_change()
# t = w.sweep(to.address)
# self.assertEqual(t.store(), tx_id)
def test_wallet_transaction_restore_saved_tx(self):
w = wallet_create_or_open('test_wallet_transaction_restore', network='bitcoinlib_test',
db_uri=self.database_uri)
wk = w.get_key()
if not USE_FASTECDSA:
self.skipTest("Need fastecdsa module with deterministic txid's to run this test")
utxos = [{
'address': wk.address,
'script': '',
'confirmations': 10,
'output_n': 1,
'txid': '9f5d4004c7cc5a31a735bddea6ff517e52f1cd700df208d2c39ddc536670f1fe',
'value': 1956783097
}]
w.utxos_update(utxos=utxos)
to = w.get_key_change()
t = w.sweep(to.address)
tx_id = t.store()
del w
wallet_empty('test_wallet_transaction_restore', db_uri=self.database_uri)
w = wallet_create_or_open('test_wallet_transaction_restore', network='bitcoinlib_test',
db_uri=self.database_uri)
w.get_key()
w.utxos_update(utxos=utxos)
to = w.get_key_change()
t = w.sweep(to.address)
self.assertEqual(t.store(), tx_id)

def test_wallet_transaction_send_keyid(self):
w = Wallet.create('wallet_send_key_id', witness_type='segwit', network='bitcoinlib_test',
Expand Down Expand Up @@ -2362,24 +2360,22 @@ def test_wallet_transaction_replace_by_fee(self):
self.assertTrue(t2.replace_by_fee)
self.assertEqual(t2.inputs[0].sequence, SEQUENCE_REPLACE_BY_FEE)

# fiXME
# def test_wallet_anti_fee_sniping(self):
# w = wallet_create_or_open('antifeesnipingtestwallet', network='testnet', db_uri=self.database_uri)
# w.utxo_add(w.get_key().address, 1234567, os.urandom(32).hex(), 1)
# t = w.send_to('tb1qrjtz22q59e76mhumy0p586cqukatw5vcd0xvvz', 123456)
# # FIXME: Bitaps and Bitgo return incorrect blockcount for testnet
# block_height = Service(network='testnet', exclude_providers=['bitgo', 'bitaps'], cache_uri='').blockcount()
# self.assertAlmostEqual(t.locktime, block_height+1, delta=3)
#
# w2 = wallet_create_or_open('antifeesnipingtestwallet2', network='testnet', anti_fee_sniping=True)
# w2.utxo_add(w2.get_key().address, 1234567, os.urandom(32).hex(), 1)
# t = w2.send_to('tb1qrjtz22q59e76mhumy0p586cqukatw5vcd0xvvz', 123456, locktime=1901070183)
# self.assertEqual(t.locktime, 1901070183)
#
# w3 = wallet_create_or_open('antifeesnipingtestwallet3', network='testnet', anti_fee_sniping=False)
# w3.utxo_add(w3.get_key().address, 1234567, os.urandom(32).hex(), 1)
# t = w3.send_to('tb1qrjtz22q59e76mhumy0p586cqukatw5vcd0xvvz', 123456)
# self.assertEqual(t.locktime, 0)
def test_wallet_anti_fee_sniping(self):
w = wallet_create_or_open('antifeesnipingtestwallet', network='testnet', db_uri=self.database_uri)
w.utxo_add(w.get_key().address, 1234567, os.urandom(32).hex(), 1)
t = w.send_to('tb1qrjtz22q59e76mhumy0p586cqukatw5vcd0xvvz', 123456)
block_height = Service(network='testnet', cache_uri='').blockcount()
self.assertAlmostEqual(t.locktime, block_height+1, delta=3)

w2 = wallet_create_or_open('antifeesnipingtestwallet2', network='testnet', anti_fee_sniping=True)
w2.utxo_add(w2.get_key().address, 1234567, os.urandom(32).hex(), 1)
t = w2.send_to('tb1qrjtz22q59e76mhumy0p586cqukatw5vcd0xvvz', 123456, locktime=1901070183)
self.assertEqual(t.locktime, 1901070183)

w3 = wallet_create_or_open('antifeesnipingtestwallet3', network='testnet', anti_fee_sniping=False)
w3.utxo_add(w3.get_key().address, 1234567, os.urandom(32).hex(), 1)
t = w3.send_to('tb1qrjtz22q59e76mhumy0p586cqukatw5vcd0xvvz', 123456)
self.assertEqual(t.locktime, 0)

@classmethod
def tearDownClass(cls):
Expand Down

0 comments on commit 1393e97

Please sign in to comment.