async def interact(self): # Just show the address... no real confirmation needed. from main import hsm_active, dis if not hsm_active: msg = self.get_msg() msg += '\n\nCompare this payment address to the one shown on your other, less-trusted, software.' if version.has_fatram: msg += ' Press 4 to view QR Code.' while 1: ch = await ux_show_story(msg, title=self.title, escape='4') if ch == '4' and version.has_fatram: q = ux.QRDisplay([self.address], (self.addr_fmt & AFC_BECH32)) await q.interact_bare() continue break else: # finish the Wait... dis.progress_bar(1) self.done() UserAuthorizedAction.cleanup() # because no results to store
async def failure(self, msg, exc=None, title='Failure'): self.failed = msg self.done() # show line number and/or simple text about error if exc: print("%s:" % msg) sys.print_exception(exc) msg += '\n\n' em = str(exc) if em: msg += em msg += '\n\n' msg += problem_file_line(exc) from main import hsm_active, dis # do nothing more for HSM case: msg will be available over USB if hsm_active: dis.progress_bar(1) # finish the Validating... or whatever was up return # may be a user-abort waiting, but we want to see error msg; so clear it ux_clear_keys(True) return await ux_show_story(msg, title)
async def do_delay(self, pa): # show # of failures and implement the delay, which could be # very long. dis.clear() dis.text(None, 0, "Checking...", FontLarge) dis.text(None, 24, 'Wait '+pretty_delay(pa.delay_required * pa.seconds_per_tick)) dis.text(None, 40, "(%d failures)" % pa.num_fails) while pa.is_delay_needed(): dis.progress_bar(pa.delay_achieved / pa.delay_required) dis.show() pa.delay()
async def test_sflash(): dis.clear() dis.text(None, 18, 'Serial Flash') dis.show() #if ckcc.is_simulator(): return from main import sf from ustruct import pack import tcc msize = 1024 * 1024 sf.chip_erase() for phase in [0, 1]: steps = 7 * 4 for i in range(steps): dis.progress_bar(i / steps) dis.show() await sleep_ms(250) if not sf.is_busy(): break assert not sf.is_busy(), "sflash erase didn't finish" # leave chip blank if phase == 1: break buf = bytearray(32) for addr in range(0, msize, 1024): sf.read(addr, buf) assert set(buf) == {255}, "sflash not blank:" + repr(buf) rnd = tcc.sha256(pack('I', addr)).digest() sf.write(addr, rnd) sf.read(addr, buf) assert buf == rnd, "sflash write failed" dis.progress_bar_show(addr / msize) # check no aliasing, also right size part for addr in range(0, msize, 1024): expect = tcc.sha256(pack('I', addr)).digest() sf.read(addr, buf) assert buf == expect, "sflash readback failed" dis.progress_bar_show(addr / msize)
async def do_delay(self, pa): # show # of failures and implement the delay, which could be # very long. from main import numpad dis.clear() dis.text(None, 0, "Checking...", FontLarge) dis.text(None, 24, 'Wait '+pretty_delay(pa.delay_required * pa.seconds_per_tick)) dis.text(None, 40, "(%d failures)" % pa.num_fails) # save a little bit of interrupt load/overhead numpad.stop() while pa.is_delay_needed(): dis.progress_bar(pa.delay_achieved / pa.delay_required) dis.show() pa.delay() numpad.start()
async def do_delay(self, pa): # show # of failures and implement the delay, which could be # very long. dis.clear() dis.text(None, 0, "Please Wait", FontLarge) dis.text(None, 24, pretty_delay(pa.delay_required * pa.seconds_per_tick)) dis.text(None, 40, "# of failures: %d" % pa.num_fails) while pa.is_delay_needed(): dis.progress_bar(pa.delay_achieved / pa.delay_required) dis.show() pa.delay() ch = ux_poll_once('x') if ch == 'x': return False return True
async def interact(self): # Prompt user w/ details and get approval from main import dis, hsm_active # step 1: parse PSBT from sflash into in-memory objects. dis.fullscreen("Validating...") try: with SFFile(TXN_INPUT_OFFSET, length=self.psbt_len) as fd: self.psbt = psbtObject.read_psbt(fd) except BaseException as exc: if isinstance(exc, MemoryError): msg = "Transaction is too complex" exc = None else: msg = "PSBT parse failed" return await self.failure(msg, exc) # Do some analysis/ validation try: await self.psbt.validate() # might do UX: accept multisig import self.psbt.consider_inputs() self.psbt.consider_keys() self.psbt.consider_outputs() except FraudulentChangeOutput as exc: print('FraudulentChangeOutput: ' + exc.args[0]) return await self.failure(exc.args[0], title='Change Fraud') except FatalPSBTIssue as exc: print('FatalPSBTIssue: ' + exc.args[0]) return await self.failure(exc.args[0]) except BaseException as exc: del self.psbt gc.collect() if isinstance(exc, MemoryError): msg = "Transaction is too complex" exc = None else: msg = "Invalid PSBT" return await self.failure(msg, exc) # step 2: figure out what we are approving, so we can get sign-off # - outputs, amounts # - fee # # notes: # - try to handle lots of outputs # - cannot calc fee as sat/byte, only as percent # - somethings are 'warnings': # - fee too big # - inputs we can't sign (no key) # try: msg = uio.StringIO() # mention warning at top wl= len(self.psbt.warnings) if wl == 1: msg.write('(1 warning below)\n\n') elif wl >= 2: msg.write('(%d warnings below)\n\n' % wl) self.output_summary_text(msg) gc.collect() fee = self.psbt.calculate_fee() if fee is not None: msg.write("\nNetwork fee:\n%s %s\n" % self.chain.render_value(fee)) # NEW: show where all the change outputs are going self.output_change_text(msg) gc.collect() if self.psbt.warnings: msg.write('\n---WARNING---\n\n') for label, m in self.psbt.warnings: msg.write('- %s: %s\n\n' % (label, m)) if self.do_visualize: # stop here and just return the text of approval message itself self.result = await self.save_visualization(msg, (self.stxn_flags & STXN_SIGNED)) del self.psbt self.done() return if not hsm_active: msg.write("\nPress OK to approve and sign transaction. X to abort.") ch = await ux_show_story(msg, title="OK TO SEND?") else: ch = await hsm_active.approve_transaction(self.psbt, self.psbt_sha, msg.getvalue()) dis.progress_bar(1) # finish the Validating... except MemoryError: # recovery? maybe. try: del self.psbt del msg except: pass # might be NameError since we don't know how far we got gc.collect() msg = "Transaction is too complex" return await self.failure(msg) if ch != 'y': # they don't want to! self.refused = True await ux_dramatic_pause("Refused.", 1) del self.psbt self.done() return # do the actual signing. try: gc.collect() self.psbt.sign_it() except FraudulentChangeOutput as exc: return await self.failure(exc.args[0], title='Change Fraud') except MemoryError: msg = "Transaction is too complex" return await self.failure(msg) except BaseException as exc: return await self.failure("Signing failed late", exc) if self.approved_cb: # for micro sd case await self.approved_cb(self.psbt) self.done() return txid = None try: # re-serialize the PSBT back out with SFFile(TXN_OUTPUT_OFFSET, max_size=MAX_TXN_LEN, message="Saving...") as fd: await fd.erase() if self.do_finalize: txid = self.psbt.finalize(fd) else: self.psbt.serialize(fd) self.result = (fd.tell(), fd.checksum.digest()) self.done(redraw=(not txid)) except BaseException as exc: return await self.failure("PSBT output failed", exc) if self.do_finalize and txid and not hsm_active: # show txid when we can; advisory await ux_show_story(txid, "Final TXID")