firmware/testing/api.py
2022-04-25 11:47:26 -04:00

176 lines
4.7 KiB
Python

# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC.
#
# Access a local bitcoin-Qt/bitcoind on testnet (must be v22 or higher)
#
# Must have these lines in the bitcoin.conf file:
#
# testnet=1
# server=1
#
import pytest, os
from bitcoinrpc.authproxy import AuthServiceProxy
from base64 import b64encode, b64decode
URL = '127.0.0.1:18332/wallet/'
def get_cookie():
# read local bitcoind cookie .. highly mac-only
AUTHFILE = '~/Library/Application Support/Bitcoin/testnet3/.cookie'
try:
cookie = open(os.path.expanduser(AUTHFILE), 'rt').read().strip()
except FileNotFoundError:
raise pytest.skip('no local bitcoind')
return cookie
@pytest.fixture(scope='function')
def bitcoind():
# JSON-RPC connection to a bitcoind instance
# see <https://github.com/jgarzik/python-bitcoinrpc>
cookie = get_cookie()
conn = AuthServiceProxy('http://' + cookie + '@' + URL)
assert conn.getblockchaininfo()['chain'] == 'test'
assert conn.getnetworkinfo()['version'] >= 220000, "we require >= 22.0 of Core"
return conn
@pytest.fixture
def match_key(bitcoind, set_master_key, reset_seed_words):
# load simulator w/ existing bip32 master key of testnet instance
# bummer: dumpmasterprivkey RPC call was removed!
#prv = bitcoind.dumpmasterprivkey()
def doit():
print("match_key: doit()")
from tempfile import mktemp
fn = mktemp()
bitcoind.dumpwallet(fn)
prv = None
for ln in open(fn, 'rt').readlines():
if 'extended private masterkey' in ln:
assert not prv
prv = ln.split(": ", 1)[1].strip()
os.unlink(fn)
assert prv.startswith('tprv')
xfp = set_master_key(prv)
return xfp
# NOTE: set_master_key does teardown/reset
return doit
@pytest.fixture()
def bitcoind_finalizer(bitcoind):
# Use bitcoind to finalize a PSBT and get out txn
def doit(psbt, extract=True):
rv = bitcoind.finalizepsbt(b64encode(psbt).decode('ascii'), extract)
return b64decode(rv.get('psbt', '')), rv.get('hex'), rv['complete']
return doit
@pytest.fixture()
def bitcoind_analyze(bitcoind):
# Use bitcoind to finalize a PSBT and get out txn
def doit(psbt):
return bitcoind.analyzepsbt(b64encode(psbt).decode('ascii'))
return doit
@pytest.fixture()
def bitcoind_decode(bitcoind):
# Use bitcoind to finalize a PSBT and get out txn
def doit(psbt):
return bitcoind.decodepsbt(b64encode(psbt).decode('ascii'))
return doit
@pytest.fixture()
def explora():
def doit(*parts):
import urllib.request
import json
url = 'https://blockstream.info/testnet/api/' + '/'.join(parts)
with urllib.request.urlopen(url) as response:
return json.load(response)
return doit
@pytest.fixture(scope='function')
def bitcoind_wallet(bitcoind):
# Use bitcoind to create a temporary wallet file, and then do cleanup after
# - wallet will not have any keys, and is watch-only
import os, shutil
fname = '/tmp/ckcc-test-wallet-%d' % os.getpid()
disable_private_keys = True
blank = True
w = bitcoind.createwallet(fname, disable_private_keys, blank)
assert w['name'] == fname
# give them an object they can do API calls w/ rpcwallet filled-in
cookie = get_cookie()
url = 'http://' + cookie + '@' + URL + '/wallet/' + fname.replace('/', '%2f')
#print(url)
conn = AuthServiceProxy(url)
assert conn.getblockchaininfo()['chain'] == 'test'
yield conn
# cleanup
bitcoind.unloadwallet(fname)
assert fname.startswith('/tmp/ckcc-test-wallet')
shutil.rmtree(fname)
@pytest.fixture(scope='function')
def bitcoind_d_wallet(bitcoind):
# Use bitcoind to create a temporary DESCRIPTOR-based wallet file, and then do cleanup after
# - wallet will not have any keys until a descriptor is added, and is not just watch-only
import os, shutil
fname = '/tmp/ckcc-test-desc-wallet-%d' % os.getpid()
disable_private_keys = True
blank = True
password = None
avoid_reuse = False
descriptors = True
w = bitcoind.createwallet(fname, disable_private_keys, blank,
password, avoid_reuse, descriptors)
assert w['name'] == fname
# give them an object they can do API calls w/ rpcwallet filled-in
cookie = get_cookie()
url = 'http://' + cookie + '@' + URL + '/wallet/' + fname.replace('/', '%2f')
#print(url)
conn = AuthServiceProxy(url)
assert conn.getblockchaininfo()['chain'] == 'test'
yield conn
# cleanup
bitcoind.unloadwallet(fname)
assert fname.startswith('/tmp/ckcc-test-desc-wallet')
shutil.rmtree(fname)
# EOF