mk4 changes

This commit is contained in:
Peter D. Gray 2021-09-07 08:20:47 -04:00
parent 28cffb543a
commit 5b0cd6fc5f
No known key found for this signature in database
GPG Key ID: F0E6CC6AFC16CF7B
16 changed files with 204 additions and 24 deletions

View File

@ -20,7 +20,7 @@ def pytest_addoption(parser):
parser.addoption("--manual", action="store_true",
default=False, help="operator must press keys on real CC")
parser.addoption("--mk", default=3, help="Assume mark N hardware")
parser.addoption("--mk", default=4, help="Assume mark N hardware")
parser.addoption("--duress", action="store_true",
default=False, help="assume logged-in with duress PIN")
@ -64,8 +64,9 @@ def simulator(request):
def sim_exec(dev):
# run code in the simulator's interpretor
def doit(cmd):
def doit(cmd, binary=False):
s = dev.send_recv(b'EXEC' + cmd.encode('utf-8'))
if binary: return s
return s.decode('utf-8') if not isinstance(s, str) else s
return doit
@ -574,7 +575,7 @@ def reset_seed_words(sim_exec, sim_execfile, simulator):
def settings_set(sim_exec):
def doit(key, val):
x = sim_exec("nvstore.settings.set('%s', %r)" % (key, val))
x = sim_exec("settings.set('%s', %r)" % (key, val))
assert x == ''
return doit
@ -583,7 +584,7 @@ def settings_set(sim_exec):
def settings_get(sim_exec):
def doit(key):
cmd = f"RV.write(repr(nvstore.settings.get('{key}')))"
cmd = f"RV.write(repr(settings.get('{key}')))"
resp = sim_exec(cmd)
assert 'Traceback' not in resp, resp
return eval(resp)
@ -594,7 +595,7 @@ def settings_get(sim_exec):
def settings_remove(sim_exec):
def doit(key):
x = sim_exec("nvstore.settings.remove_key('%s')" % key)
x = sim_exec("settings.remove_key('%s')" % key)
assert x == ''
return doit
@ -1000,8 +1001,34 @@ def is_mark2(request):
@pytest.fixture(scope='session')
def is_mark3(request):
# better: ask it
return int(request.config.getoption('--mk')) == 3
@pytest.fixture(scope='session')
def is_mark4(request):
# better: ask it
return int(request.config.getoption('--mk')) == 4
@pytest.fixture()
def nfc_read(sim_exec):
def doit():
rv = sim_exec('RV.write(NFC.dump_ndef())', binary=True)
if b'Traceback' in rv: raise pytest.fail(rv.decode('utf-8'))
return rv
return doit
@pytest.fixture
def load_shared_mod():
# load indicated file.py as a module
# from <https://stackoverflow.com/questions/67631/how-to-import-a-module-given-the-full-path>
def doit(name, path):
import importlib.util
spec = importlib.util.spec_from_file_location(name, path)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
return mod
return doit
# useful fixtures related to multisig
from test_multisig import (import_ms_wallet, make_multisig, offer_ms_import, fake_ms_txn,
make_ms_address, clear_ms, make_myself_wallet)

View File

@ -10,7 +10,7 @@ from ubinascii import hexlify as b2a_hex
from ubinascii import unhexlify as a2b_hex
import ngu, ustruct
from nvstore import settings
from glob import settings
if 1:
# test file contents: completeness, syntax

View File

@ -3,7 +3,7 @@
# quickly main wipe seed; don't install anything new
from glob import numpad, dis
from pincodes import pa
from nvstore import settings
from glob import settings
from pincodes import AE_SECRET_LEN, PA_IS_BLANK
if not pa.is_secret_blank():

View File

@ -1,7 +1,7 @@
# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC.
#
import main
from nvstore import settings
from glob import settings
from ujson import dumps
RV.write(dumps(settings.get(main.SKEY)))

View File

@ -1,6 +1,6 @@
# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC.
#
from nvstore import settings
from glob import settings
from ujson import dumps
RV.write(dumps(settings.current))

View File

@ -11,7 +11,7 @@ from ubinascii import unhexlify as a2b_hex
import ustruct
from sflash import SF
from nvstore import SLOTS, settings
from glob import SLOTS, settings
# reset whatever's there
SF.chip_erase()

View File

@ -5,7 +5,7 @@ from sim_settings import sim_defaults
import stash, chains
from h import b2a_hex
from pincodes import pa
from nvstore import settings
from glob import settings
from stash import SecretStash, SensitiveValues
from utils import xfp2str

View File

@ -5,7 +5,7 @@ from sim_settings import sim_defaults
import stash, chains
from h import b2a_hex
from pincodes import pa
from nvstore import settings
from glob import settings
from stash import SecretStash, SensitiveValues
from utils import xfp2str

View File

@ -5,7 +5,7 @@ from sim_settings import sim_defaults
import stash, chains
from h import b2a_hex
from pincodes import pa
from nvstore import settings
from glob import settings
import stash
from seed import set_seed_value
from utils import xfp2str

View File

@ -6,7 +6,7 @@ from sim_settings import sim_defaults
import stash, chains
from h import b2a_hex
from pincodes import pa
from nvstore import settings
from glob import settings
from stash import SecretStash, SensitiveValues
from utils import xfp2str, swab32

View File

@ -10,7 +10,7 @@ from ubinascii import hexlify as b2a_hex
from ubinascii import unhexlify as a2b_hex
import ustruct
from nvstore import settings
from glob import settings
from public_constants import MAX_TXN_LEN
# load PSBT into simulated SPI Flash

View File

@ -1,7 +1,7 @@
# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC.
#
# quickly clear all multisig wallets installed
from nvstore import settings
from glob import settings
from ux import restore_menu
if settings.get('multisig'):

View File

@ -5,3 +5,8 @@ markers =
bitcoind: indicates local bitcoind (testnet) will be needed
onetime: test cant be combined with any others, likely needs board reset
veryslow: test takes more than 30 minutes realtime
# this isn't working FIXME
filterwarnings =
ignore:.*DeprecationWarning.*

View File

@ -10,3 +10,6 @@ onetimepass==1.0.1
# for QR scanning (pulls in numpy)
zbar-py==1.0.4
nfcpy==1.0.3
ndef==0.3.3

View File

@ -155,10 +155,27 @@ def test_speed_test(request, fake_txn, is_mark3, start_sign, end_sign, dev, need
print(" Tx time: %.1f" % tx_time)
print("Sign time: %.1f" % ready_time)
if 0:
# TODO: attempt to re-create the mega transaction: 5,569 inputs, one out
# see <https://bitcoin.stackexchange.com/questions/11542>
# - how big woudl PSBT be?
# - not a great test case because so slow.
def test_mega_txn(fake_txn, is_mark4, start_sign, end_sign, dev):
if not is_mark4:
raise pytest.xfail('no way')
psbt = fake_txn(5569, 1, dev.master_xpub)
open('debug/mega.psbt', 'wb').write(psbt)
_, txn = try_sign(psbt, accept=True, finalize=True)
open('debug/mega.txn', 'wb').write(txn)
@pytest.mark.parametrize('segwit', [True, False])
@pytest.mark.parametrize('out_style', ADDR_STYLES)
def test_io_size(request, decode_with_bitcoind, fake_txn, is_mark3,
def test_io_size(request, decode_with_bitcoind, fake_txn, is_mark3, is_mark4,
start_sign, end_sign, dev, segwit, out_style, accept = True):
# try a bunch of different bigger sized txns
@ -170,14 +187,15 @@ def test_io_size(request, decode_with_bitcoind, fake_txn, is_mark3,
# - only mk3 can do full amounts
# - time on mk3, v4.0.0 firmware: 13 minutes
if not is_mark3:
num_in = 10
num_out = 10
else:
num_in = 10
num_out = 10
if is_mark3:
num_in = 20
num_out = 250
elif is_mark4:
num_in = 250
num_out = 2000
psbt = fake_txn(num_in, num_out, dev.master_xpub, segwit_in=segwit, outstyles=[out_style])
@ -196,6 +214,8 @@ def test_io_size(request, decode_with_bitcoind, fake_txn, is_mark3,
signed = end_sign(accept, finalize=True)
open('debug/signed.txn', 'wb').write(signed)
decoded = decode_with_bitcoind(signed)
#print("Bitcoin code says:", end=''); pprint(decoded)
@ -1170,7 +1190,7 @@ def test_txid_calc(num_ins, fake_txn, try_sign, dev, segwit, decode_with_bitcoin
title, story = cap_story()
assert '0' in story
assert 'TXID' in title, story
txid = story.strip()
txid = story.split()[0]
if 1:
# compare to PyCoin
@ -1395,4 +1415,48 @@ def test_value_render(units, fake_txn, start_sign, cap_story, settings_set, sett
settings_remove('rz')
@pytest.mark.parametrize('num_outs', [ 1, 20, 250])
def test_nfc_after(num_outs, fake_txn, try_sign, nfc_read, need_keypress, cap_story):
# Read signing result over NFC, decode it.
import ndef
from hashlib import sha256
psbt = fake_txn(1, num_outs)
orig, result = try_sign(psbt, accept=True, finalize=True)
too_big = len(result) > 8000
if too_big: assert num_outs > 100
if num_outs > 100: assert too_big
time.sleep(.1)
title, story = cap_story()
assert 'TXID' in title, story
txid = a2b_hex(story.split()[0])
assert 'Press 3' in story
need_keypress('3')
if too_big:
title, story = cap_story()
assert 'is too large' in story
return
contents = nfc_read()
#need_keypress('x')
#print("contents = " + B2A(contents))
for got in ndef.message_decoder(contents):
if got.type == 'urn:nfc:wkt:T':
assert 'Transaction' in got.text
assert b2a_hex(txid).decode() in got.text
elif got.type == 'urn:nfc:ext:bitcoin.org:txid':
assert got.data == txid
elif got.type == 'urn:nfc:ext:bitcoin.org:txn':
assert got.data == result
elif got.type == 'urn:nfc:ext:bitcoin.org:sha256':
assert got.data == sha256(result).digest()
else:
raise ValueError(got.type)
# EOF

View File

@ -239,5 +239,86 @@ def test_match_deriv_path(patterns, paths, answers, sim_exec):
rv = sim_exec(cmd)
assert rv == str(bool(ans))
@pytest.mark.parametrize('case', range(6))
def test_ndef(case, load_shared_mod):
# NDEF unit tests
import ndef
from struct import pack, unpack
from binascii import b2a_hex
def get_body(efile):
# unwrap CC_FILE and cruft
assert efile[-1] == 0xfe
assert efile[0] == 0xE2
st = len(cc_ndef.CC_FILE)
if efile[st] == 0xff:
xl = unpack('>H', efile[st+1:st+3])[0]
st += 3
else:
xl = efile[st]
st += 1
body = efile[st:-1]
assert len(body) == xl
return body
def decode(msg):
return list(ndef.message_decoder(get_body(msg)))
cc_ndef = load_shared_mod('cc_ndef', '../shared/ndef.py')
n = cc_ndef.ndefMaker()
if case == 0:
n.add_text("Hello world")
got, = decode(n.bytes())
assert got.type == 'urn:nfc:wkt:T'
assert got.text == 'Hello world'
assert got.language == 'en'
assert got.encoding == 'UTF-8'
elif case == 1:
n.add_text("Hello world")
n.add_url("store.coinkite.com/store/coldcard")
txt,url = decode(n.bytes())
assert txt.text == 'Hello world'
assert url.type == 'urn:nfc:wkt:U'
assert url.uri == 'https://store.coinkite.com/store/coldcard' == url.iri
elif case == 2:
hx = b2a_hex(bytes(range(32)))
n.add_text("Title")
n.add_custom('bitcoin.org:sha256', hx)
txt,sha = decode(n.bytes())
assert txt.text == 'Title'
assert sha.data == hx
elif case == 3:
psbt = b'psbt\xff' + bytes(5000)
n.add_text("Title")
n.add_custom('bitcoin.org:psbt', psbt)
n.add_text("Footer")
txt,p,ft = decode(n.bytes())
assert txt.text == 'Title'
assert ft.text == 'Footer'
assert p.data == psbt
assert p.type == 'urn:nfc:ext:bitcoin.org:psbt'
elif case == 4:
hx = b2a_hex(bytes(range(32)))
n.add_custom('bitcoin.org:txid', hx)
got, = decode(n.bytes())
assert got.type == 'urn:nfc:ext:bitcoin.org:txid'
assert got.data == hx
elif case == 5:
hx = bytes(2000)
n.add_custom('bitcoin.org:txn', hx)
got, = decode(n.bytes())
assert got.type == 'urn:nfc:ext:bitcoin.org:txn'
assert got.data == hx
# EOF