share push tx tests

This commit is contained in:
scgbckbone 2024-06-19 08:54:19 +02:00 committed by doc-hex
parent 1abb04f928
commit e1a17ac43f
5 changed files with 84 additions and 31 deletions

View File

@ -625,7 +625,7 @@ class ApproveTransaction(UserAuthorizedAction):
return '%s\n - to script -\n%s\n' % (val, dest)
@staticmethod
async def try_push_tx(data, txid, txn_sha):
async def try_push_tx(data, txid, txn_sha=None):
from glob import settings, PSRAM, NFC
# if NFC PushTx is enabled, do that w/o questions.
url = settings.get('ptxurl', False)
@ -633,6 +633,8 @@ class ApproveTransaction(UserAuthorizedAction):
try:
if isinstance(data, int):
data = PSRAM.read_at(TXN_OUTPUT_OFFSET, data)
if txn_sha is None:
txn_sha = ngu.hash.sha256s(data)[-8:]
await NFC.share_push_tx(url, txid, data, txn_sha)
return True
except: pass # continue normally if it fails, perhaps too big?
@ -1181,8 +1183,10 @@ async def sign_psbt_file(filename, force_vdisk=False, slot_b=None):
base+'-final.txn' if not del_after else 'tmp.txn', out_path)
with SFFile(TXN_OUTPUT_OFFSET, max_size=MAX_TXN_LEN, message="Saving...") as fd0:
await fd0.erase()
txid = psbt.finalize(fd0)
tx_len, tx_sha = (fd0.tell(), fd0.checksum.digest())
fd0.close()
tx_len, tx_sha = fd0.tell(), fd0.checksum.digest()
if txid and await ApproveTransaction.try_push_tx(tx_len, txid, tx_sha):
return # success, exit

View File

@ -587,6 +587,7 @@ class NFCHandler:
else:
psbt.serialize(fd)
fd.close()
self.result = (fd.tell(), fd.checksum.digest())
out_len, out_sha = self.result

View File

@ -975,7 +975,7 @@ async def qr_psbt_sign(decoder, psbt_len, raw):
txid = psbt.finalize(fd)
else:
psbt.serialize(fd)
psram.close()
data_len = psram.tell()
sha = fd.checksum.digest()

View File

@ -441,7 +441,7 @@ def cap_image(request, sim_exec, is_q1, is_headless):
if is_headless:
raise pytest.skip("headless mode: QR tests disabled")
# trigger simulator to capture a snapshot into a named file, read it.
fn = os.path.realpath(f'./debug/snap-{random.randint(1E6, 9E6)}.png')
fn = os.path.realpath(f'./debug/snap-{random.randint(int(1E6), int(9E6))}.png')
try:
sim_exec(f"from glob import dis; dis.dis.save_snapshot({fn!r})")
for _ in range(20):
@ -1167,11 +1167,13 @@ def check_against_bitcoind(bitcoind, use_regtest, sim_exec, sim_execfile):
return doit
@pytest.fixture
def try_sign_microsd(open_microsd, cap_story, pick_menu_item, goto_home, need_keypress, microsd_path):
def try_sign_microsd(open_microsd, cap_story, pick_menu_item, goto_home,
need_keypress, microsd_path, cap_screen):
# like "try_sign" but use "air gapped" file transfer via microSD
def doit(f_or_data, accept=True, finalize=False, accept_ms_import=False, complete=False, encoding='binary', del_after=0):
def doit(f_or_data, accept=True, finalize=False, accept_ms_import=False,
complete=False, encoding='binary', del_after=0, nfc_push_tx=False):
if f_or_data[0:5] == b'psbt\xff':
ip = f_or_data
filename = 'memory'
@ -1229,6 +1231,9 @@ def try_sign_microsd(open_microsd, cap_story, pick_menu_item, goto_home, need_ke
# look for "Aborting..." ??
return ip, None, None
if nfc_push_tx:
return ip, None, None
# wait for it to finish
for r in range(10):
time.sleep(0.1)

View File

@ -13,7 +13,7 @@ from struct import pack, unpack
import ndef
from hashlib import sha256
from txn import *
from charcodes import KEY_NFC
from charcodes import KEY_NFC, KEY_QR
@pytest.mark.parametrize('case', range(6))
@ -158,7 +158,7 @@ def try_sign_nfc(cap_story, pick_menu_item, goto_home, need_keypress,
sim_exec('from pyb import SDCard; SDCard.ejected = True; import nfc; nfc.NFCHandler.startup()')
def doit(f_or_data, accept=True, expect_finalize=False, accept_ms_import=False,
complete=False, encoding='binary', over_nfc=True):
complete=False, encoding='binary', over_nfc=True, nfc_tools=False, nfc_push_tx=False):
if f_or_data[0:5] == b'psbt\xff':
ip = f_or_data
@ -198,14 +198,20 @@ def try_sign_nfc(cap_story, pick_menu_item, goto_home, need_keypress,
time.sleep(.2) # required
goto_home()
pick_menu_item('Ready To Sign')
if nfc_tools:
pick_menu_item("Advanced/Tools")
pick_menu_item("NFC Tools")
pick_menu_item("Sign PSBT")
else:
pick_menu_item('Ready To Sign')
time.sleep(.1)
_, story = cap_story()
assert 'NFC' in story
time.sleep(.1)
_, story = cap_story()
assert 'NFC' in story
press_nfc()
time.sleep(.1)
press_nfc()
time.sleep(.1)
nfc_write(ccfile)
time.sleep(.5)
@ -230,6 +236,10 @@ def try_sign_nfc(cap_story, pick_menu_item, goto_home, need_keypress,
# look for "Aborting..." ??
return ip, None, None
time.sleep(.1)
if nfc_push_tx:
return ip, None, None
if not over_nfc:
# wait for it to finish
for r in range(10):
@ -417,40 +427,73 @@ def test_ndef_roundtrip(load_shared_mod):
assert cc_ndef.ccfile_decode(r) == (12, 399, False, 4096)
@pytest.mark.parametrize('num_outs', [2, 100, 250])
@pytest.mark.parametrize('num_outs', [2, 5, 100, 250])
@pytest.mark.parametrize('chain', ['BTC', 'XTN'])
@pytest.mark.parametrize('way', ['sd', 'nfc', 'usb', 'qr'])
def test_nfc_pushtx(num_outs, chain, enable_nfc, settings_set, settings_remove,
try_sign, fake_txn, nfc_block4rf, nfc_read, press_cancel,
cap_story, cap_screen, has_qwerty
):
cap_story, cap_screen, has_qwerty, way, try_sign_microsd,
try_sign_nfc, scan_a_qr, need_keypress, press_select,
goto_home):
# check the NFC push Tx feature, validating the URL's it makes
# - not the UX
# - 100 outs => 5000 or so
# - 250 outs => 8800
# - not too many inputs so faster to sign
from base64 import urlsafe_b64decode
from urllib.parse import urlsplit, urlunsplit, parse_qsl, unquote
from urllib.parse import urlsplit, parse_qsl, unquote
settings_set('chain', chain)
enable_nfc()
if way in ("nfc", "qr") and num_outs >= 100:
raise pytest.skip("too big")
prefix = 'http://10.0.0.10/pushtx#'
settings_set('ptxurl', prefix)
psbt = fake_txn(2, num_outs)
_, result = try_sign(psbt, finalize=True)
if way == "usb":
_, result = try_sign(psbt, finalize=True)
elif way == "sd":
ip, result, txid = try_sign_microsd(psbt, finalize=True, nfc_push_tx=True)
elif way == "nfc":
ip, result, txid = try_sign_nfc(psbt, expect_finalize=True, nfc_tools=True,
nfc_push_tx=True)
elif way == "qr":
goto_home()
need_keypress(KEY_QR)
from bbqr import split_qrs
actual_vers, parts = split_qrs(psbt, 'P')
for p in parts:
scan_a_qr(p)
time.sleep(4.0 / len(parts)) # just so we can watch
print(f'len = {len(result)}')
for r in range(20):
title, story = cap_story()
if 'OK TO SEND' in title:
break
time.sleep(.1)
else:
raise pytest.fail('never saw it?')
# approve it
press_select()
# print(f'len = {len(result)}')
#
if num_outs >= 250:
# NFC will not be offered (too big)
assert len(result) > 8000
time.sleep(.1)
title, story = cap_story()
assert title == 'Final TXID'
assert 'to share signed txn' in story
if way == "usb":
assert title == 'Final TXID'
assert 'to share signed txn' in story
elif way == "sd":
assert title == "PSBT Signed"
else:
assert False
return
# expect NFC animation
@ -495,15 +538,15 @@ def test_nfc_pushtx(num_outs, chain, enable_nfc, settings_set, settings_remove,
expect = sha256(decoded_txn).digest()[-8:]
assert expect == decoded_chk
assert result == decoded_txn
settings_remove('ptxurl')
settings_set('chain', 'XTN')
def test_share_by_pushtx(goto_home, cap_story, pick_menu_item, settings_set, settings_remove,
microsd_path, cap_menu, has_qwerty, cap_screen,
press_cancel, enable_nfc, nfc_block4rf, nfc_read):
@pytest.mark.parametrize("is_hex", [True, False])
def test_share_by_pushtx(goto_home, cap_story, pick_menu_item, settings_set,
settings_remove, microsd_path, cap_menu, has_qwerty,
cap_screen, press_cancel, enable_nfc, nfc_block4rf,
nfc_read, is_hex):
enable_nfc()
@ -514,7 +557,7 @@ def test_share_by_pushtx(goto_home, cap_story, pick_menu_item, settings_set, set
fname = "fake-nfc.txn"
with open(microsd_path(fname), "wb") as f:
f.write(fake_txn)
f.write(b2a_hex(fake_txn) if is_hex else fake_txn)
goto_home()
pick_menu_item("Advanced/Tools")