Skip to content

Commit ec77347

Browse files
committed
fixup! feat(core): re-enable THP ACK piggybacking
1 parent 8bf140e commit ec77347

3 files changed

Lines changed: 100 additions & 96 deletions

File tree

core/src/trezor/wire/thp/channel.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ async def recv_payload(
262262
if control_byte.is_ack(ctrl_byte):
263263
handle_ack(self, control_byte.get_ack_bit(ctrl_byte))
264264
if return_after_ack:
265+
self._log("Standalone ACK", logger=log.error)
265266
assert not payload
266267
return EMPTY_ACK_PAYLOAD
267268
continue

python/src/trezorlib/btc.py

Lines changed: 86 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -326,96 +326,97 @@ def sign_tx(
326326
elif preauthorized:
327327
session.call(messages.DoPreauthorized(), expect=messages.PreauthorizedRequest)
328328

329-
res = session.call(signtx, expect=messages.TxRequest)
330-
331-
# Prepare structure for signatures
332-
signatures: List[Optional[bytes]] = [None] * len(inputs)
333-
serialized_tx = b""
334-
335-
def copy_tx_meta(tx: messages.TransactionType) -> messages.TransactionType:
336-
tx_copy = copy(tx)
337-
# clear fields
338-
tx_copy.inputs_cnt = len(tx.inputs)
339-
tx_copy.inputs = []
340-
tx_copy.outputs_cnt = len(tx.bin_outputs or tx.outputs)
341-
tx_copy.outputs = []
342-
tx_copy.bin_outputs = []
343-
tx_copy.extra_data_len = len(tx.extra_data or b"")
344-
tx_copy.extra_data = None
345-
return tx_copy
346-
347-
this_tx = messages.TransactionType(
348-
inputs=inputs,
349-
outputs=outputs,
350-
inputs_cnt=len(inputs),
351-
outputs_cnt=len(outputs),
352-
# pick either kw-provided or default value from the SignTx request
353-
version=signtx.version,
354-
)
329+
with session.interact() as ctx:
330+
res = ctx.call(signtx, expect=messages.TxRequest)
331+
332+
# Prepare structure for signatures
333+
signatures: List[Optional[bytes]] = [None] * len(inputs)
334+
serialized_tx = b""
335+
336+
def copy_tx_meta(tx: messages.TransactionType) -> messages.TransactionType:
337+
tx_copy = copy(tx)
338+
# clear fields
339+
tx_copy.inputs_cnt = len(tx.inputs)
340+
tx_copy.inputs = []
341+
tx_copy.outputs_cnt = len(tx.bin_outputs or tx.outputs)
342+
tx_copy.outputs = []
343+
tx_copy.bin_outputs = []
344+
tx_copy.extra_data_len = len(tx.extra_data or b"")
345+
tx_copy.extra_data = None
346+
return tx_copy
347+
348+
this_tx = messages.TransactionType(
349+
inputs=inputs,
350+
outputs=outputs,
351+
inputs_cnt=len(inputs),
352+
outputs_cnt=len(outputs),
353+
# pick either kw-provided or default value from the SignTx request
354+
version=signtx.version,
355+
)
355356

356-
R = messages.RequestType
357-
while True:
358-
# If there's some part of signed transaction, let's add it
359-
if res.serialized:
360-
if res.serialized.serialized_tx:
361-
serialized_tx += res.serialized.serialized_tx
362-
363-
if res.serialized.signature_index is not None:
364-
idx = res.serialized.signature_index
365-
sig = res.serialized.signature
366-
if signatures[idx] is not None:
367-
raise ValueError(f"Signature for index {idx} already filled")
368-
signatures[idx] = sig
369-
370-
if res.request_type == R.TXFINISHED:
371-
break
372-
373-
assert res.details is not None, "device did not provide details"
374-
375-
# Device asked for one more information, let's process it.
376-
if res.details.tx_hash is not None:
377-
if res.details.tx_hash not in prev_txes:
378-
raise ValueError(
379-
f"Previous transaction {res.details.tx_hash.hex()} not available"
380-
)
381-
current_tx = prev_txes[res.details.tx_hash]
382-
else:
383-
current_tx = this_tx
357+
R = messages.RequestType
358+
while True:
359+
# If there's some part of signed transaction, let's add it
360+
if res.serialized:
361+
if res.serialized.serialized_tx:
362+
serialized_tx += res.serialized.serialized_tx
363+
364+
if res.serialized.signature_index is not None:
365+
idx = res.serialized.signature_index
366+
sig = res.serialized.signature
367+
if signatures[idx] is not None:
368+
raise ValueError(f"Signature for index {idx} already filled")
369+
signatures[idx] = sig
370+
371+
if res.request_type == R.TXFINISHED:
372+
break
373+
374+
assert res.details is not None, "device did not provide details"
375+
376+
# Device asked for one more information, let's process it.
377+
if res.details.tx_hash is not None:
378+
if res.details.tx_hash not in prev_txes:
379+
raise ValueError(
380+
f"Previous transaction {res.details.tx_hash.hex()} not available"
381+
)
382+
current_tx = prev_txes[res.details.tx_hash]
383+
else:
384+
current_tx = this_tx
384385

385-
if res.request_type == R.TXPAYMENTREQ:
386-
assert res.details.request_index is not None
387-
msg = payment_reqs[res.details.request_index]
388-
res = session.call(msg, expect=messages.TxRequest)
389-
else:
390-
msg = messages.TransactionType()
391-
if res.request_type == R.TXMETA:
392-
msg = copy_tx_meta(current_tx)
393-
elif res.request_type in (R.TXINPUT, R.TXORIGINPUT):
394-
assert res.details.request_index is not None
395-
msg.inputs = [current_tx.inputs[res.details.request_index]]
396-
elif res.request_type == R.TXOUTPUT:
386+
if res.request_type == R.TXPAYMENTREQ:
397387
assert res.details.request_index is not None
398-
if res.details.tx_hash:
399-
msg.bin_outputs = [
400-
current_tx.bin_outputs[res.details.request_index]
401-
]
402-
else:
403-
msg.outputs = [current_tx.outputs[res.details.request_index]]
404-
elif res.request_type == R.TXORIGOUTPUT:
405-
assert res.details.request_index is not None
406-
msg.outputs = [current_tx.outputs[res.details.request_index]]
407-
elif res.request_type == R.TXEXTRADATA:
408-
assert res.details.extra_data_offset is not None
409-
assert res.details.extra_data_len is not None
410-
assert current_tx.extra_data is not None
411-
o, l = res.details.extra_data_offset, res.details.extra_data_len
412-
msg.extra_data = current_tx.extra_data[o : o + l]
388+
msg = payment_reqs[res.details.request_index]
389+
res = ctx.call(msg, expect=messages.TxRequest)
413390
else:
414-
raise exceptions.TrezorException(
415-
f"Unknown request type - {res.request_type}."
416-
)
391+
msg = messages.TransactionType()
392+
if res.request_type == R.TXMETA:
393+
msg = copy_tx_meta(current_tx)
394+
elif res.request_type in (R.TXINPUT, R.TXORIGINPUT):
395+
assert res.details.request_index is not None
396+
msg.inputs = [current_tx.inputs[res.details.request_index]]
397+
elif res.request_type == R.TXOUTPUT:
398+
assert res.details.request_index is not None
399+
if res.details.tx_hash:
400+
msg.bin_outputs = [
401+
current_tx.bin_outputs[res.details.request_index]
402+
]
403+
else:
404+
msg.outputs = [current_tx.outputs[res.details.request_index]]
405+
elif res.request_type == R.TXORIGOUTPUT:
406+
assert res.details.request_index is not None
407+
msg.outputs = [current_tx.outputs[res.details.request_index]]
408+
elif res.request_type == R.TXEXTRADATA:
409+
assert res.details.extra_data_offset is not None
410+
assert res.details.extra_data_len is not None
411+
assert current_tx.extra_data is not None
412+
o, l = res.details.extra_data_offset, res.details.extra_data_len
413+
msg.extra_data = current_tx.extra_data[o : o + l]
414+
else:
415+
raise exceptions.TrezorException(
416+
f"Unknown request type - {res.request_type}."
417+
)
417418

418-
res = session.call(messages.TxAck(tx=msg), expect=messages.TxRequest)
419+
res = ctx.call(messages.TxAck(tx=msg), expect=messages.TxRequest)
419420

420421
for i, sig in zip(inputs, signatures):
421422
if i.script_type != messages.InputScriptType.EXTERNAL and sig is None:

python/src/trezorlib/device.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
from .tools import Address, parse_path, workflow
3232

3333
if TYPE_CHECKING:
34-
from .client import Session
34+
from .client import InteractionContext, Session
3535

3636

3737
RECOVERY_BACK = "\x08" # backspace character, sent literally
@@ -77,16 +77,17 @@ def apply_settings(
7777

7878
if homescreen and session.version >= HOMESCREEN_STREAMING_MIN_VERSION:
7979
settings.homescreen_length = len(homescreen)
80-
response = session.call(settings, expect=messages.DataChunkRequest)
81-
_send_chunked_data(session, response, homescreen)
80+
with session.interact() as ctx:
81+
response = ctx.call(settings, expect=messages.DataChunkRequest)
82+
_send_chunked_data(ctx, response, homescreen)
8283
else:
8384
settings.homescreen = homescreen
8485
session.call(settings, expect=messages.Success)
8586
session.refresh_features()
8687

8788

8889
def _send_chunked_data(
89-
session: "Session",
90+
ctx: "InteractionContext",
9091
request: "messages.DataChunkRequest",
9192
language_data: bytes,
9293
) -> None:
@@ -96,7 +97,7 @@ def _send_chunked_data(
9697
data_length = response.data_length
9798
data_offset = response.data_offset
9899
chunk = language_data[data_offset : data_offset + data_length]
99-
response = session.call(messages.DataChunkAck(data_chunk=chunk))
100+
response = ctx.call(messages.DataChunkAck(data_chunk=chunk))
100101

101102

102103
@workflow()
@@ -108,12 +109,13 @@ def change_language(
108109
data_length = len(language_data)
109110
msg = messages.ChangeLanguage(data_length=data_length, show_display=show_display)
110111

111-
response = session.call(msg)
112-
if data_length > 0:
113-
response = messages.DataChunkRequest.ensure_isinstance(response)
114-
_send_chunked_data(session, response, language_data)
115-
else:
116-
messages.Success.ensure_isinstance(response)
112+
with session.interact() as ctx:
113+
response = ctx.call(msg)
114+
if data_length > 0:
115+
response = messages.DataChunkRequest.ensure_isinstance(response)
116+
_send_chunked_data(ctx, response, language_data)
117+
else:
118+
messages.Success.ensure_isinstance(response)
117119
session.refresh_features() # changing the language in features
118120

119121

0 commit comments

Comments
 (0)