Skip to content

Commit 99f1e06

Browse files
committed
fix(solana): split versioned-v0 test into static-verified and ALT-opaque cases
The old test_solana_sign_versioned_v0_opaque built a v0 tx whose instruction only touched static accounts (no address table lookups) and asserted it must be rejected without AdvancedMode. That's the pre-clearsign assumption; firmware now treats static-only v0 messages as fully verifiable (same as legacy) and clear-signs them directly. Split into: - test_solana_sign_versioned_v0_static_verified: static-only v0 clear-signs without AdvancedMode. - test_solana_sign_versioned_v0_opaque: a v0 tx whose instruction resolves an account via the address lookup table (genuinely unverifiable) still requires AdvancedMode.
1 parent 4ceec46 commit 99f1e06

1 file changed

Lines changed: 65 additions & 4 deletions

File tree

tests/test_msg_solana_signtx.py

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -625,9 +625,11 @@ def test_solana_path_wrong_coin_type(self):
625625
# Versioned transaction test
626626
# ================================================================
627627

628-
def test_solana_sign_versioned_v0_opaque(self):
629-
"""Versioned v0 transaction (first byte 0x80) — should require AdvancedMode
630-
for blind/opaque signing since firmware cannot parse address lookup tables."""
628+
def test_solana_sign_versioned_v0_static_verified(self):
629+
"""Versioned v0 transaction whose instructions only touch static
630+
accounts (no address lookup table references) is exactly as
631+
verifiable as a legacy message — it clear-signs without requiring
632+
AdvancedMode."""
631633
self.requires_fullFeature()
632634
self.setup_mnemonic_allallall()
633635

@@ -672,7 +674,66 @@ def test_solana_sign_versioned_v0_opaque(self):
672674

673675
raw_tx = bytes(tx)
674676

675-
# Without AdvancedMode, versioned tx should be rejected
677+
self.client.apply_policy('AdvancedMode', False)
678+
resp = self.client.call(messages.SolanaSignTx(
679+
address_n=parse_path("m/44'/501'/0'/0'"),
680+
raw_tx=raw_tx,
681+
))
682+
self.assertEqual(len(resp.signature), 64)
683+
self.assertFalse(all(b == 0 for b in resp.signature))
684+
685+
def test_solana_sign_versioned_v0_opaque(self):
686+
"""Versioned v0 transaction whose instruction reaches into an address
687+
lookup table (an account index at or beyond the static account
688+
count) cannot be verified on-device — requires AdvancedMode for
689+
blind/opaque signing."""
690+
self.requires_fullFeature()
691+
self.setup_mnemonic_allallall()
692+
693+
from_pubkey = self._get_from_pubkey()
694+
695+
system_program = self.SYSTEM_PROGRAM
696+
blockhash = b'\xBB' * 32
697+
lookup_table = b'\x33' * 32
698+
699+
tx = bytearray()
700+
tx.append(0x80) # version prefix: v0
701+
702+
# Header
703+
tx.append(1) # num_required_sigs
704+
tx.append(0) # num_readonly_signed
705+
tx.append(1) # num_readonly_unsigned
706+
707+
# 2 static accounts — the transfer destination is resolved via the
708+
# address lookup table below, not listed here.
709+
tx.append(2)
710+
tx.extend(from_pubkey)
711+
tx.extend(system_program)
712+
713+
# Recent blockhash
714+
tx.extend(blockhash)
715+
716+
# 1 instruction referencing account index 2 — beyond the 2 static
717+
# accounts, so it resolves via the address lookup table.
718+
tx.append(1)
719+
tx.append(1) # program_id index (system_program)
720+
tx.append(2) # 2 account indices
721+
tx.append(0) # from (static)
722+
tx.append(2) # to (external — loaded from the ALT)
723+
instr_data = struct.pack('<I', 2) + struct.pack('<Q', 1000000000)
724+
tx.append(len(instr_data))
725+
tx.extend(instr_data)
726+
727+
# Address table lookups: 1 entry, 1 writable index
728+
tx.append(1)
729+
tx.extend(lookup_table)
730+
tx.append(1) # writable_count
731+
tx.append(0) # writable index 0 (into the ALT)
732+
tx.append(0) # readonly_count
733+
734+
raw_tx = bytes(tx)
735+
736+
# Without AdvancedMode, an ALT-referencing versioned tx should be rejected
676737
self.client.apply_policy('AdvancedMode', False)
677738
with pytest.raises(CallException):
678739
self.client.call(messages.SolanaSignTx(

0 commit comments

Comments
 (0)