Skip to content

feat: add Solana protocol support (GetAddress, SignTx, SignMessage) - #3

Closed
BitHighlander wants to merge 9 commits into
masterfrom
feature/solana
Closed

feat: add Solana protocol support (GetAddress, SignTx, SignMessage)#3
BitHighlander wants to merge 9 commits into
masterfrom
feature/solana

Conversation

@BitHighlander

Copy link
Copy Markdown
Owner

Summary

  • Add solana_get_address(), solana_sign_tx(), solana_sign_message() client methods
  • Generate messages_solana_pb2.py using docker_build_pb.sh (protoc 3.5.1 via kktech/firmware:v8)
  • Regenerate messages_pb2.py with Solana MessageType entries (750-755)
  • Add Solana routing in mapping.py
  • Point device-protocol submodule at feature-solana branch (adds messages-solana.proto)

Protocol Messages

ID Message Direction
750 SolanaGetAddress wire_in
751 SolanaAddress wire_out
752 SolanaSignTx wire_in
753 SolanaSignedTx wire_out
754 SolanaSignMessage wire_in
755 SolanaMessageSignature wire_out

Depends on: fix/combined-cleanup being merged first

Test plan

  • docker_build_pb.sh regenerates all pb2 files cleanly
  • solana_get_address returns Base58 address against emulator
  • solana_sign_tx signs a SOL transfer against emulator
  • solana_sign_message produces valid Ed25519 signature
BitHighlander and others added 6 commits March 17, 2026 01:30
Tests for structured TRX transfer, legacy raw_data blind-sign,
TRC-20 USDT transfer, and missing field rejection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests for structured transfer, transfer with comment, legacy raw_tx
blind-sign, deterministic cell hash, and missing field rejection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests for system transfer, token info metadata, message signing,
deterministic signatures, and empty tx rejection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use @unittest.skipUnless guards so these tests are skipped gracefully
when protobuf messages are not available in the build, rather than
failing with import/mapping errors.
The MayachainGetAddress class imports fine but may not be registered
in map_class_to_type if MessageType enum lacks the entry. Check the
actual dispatch dict to decide whether to skip the test.
@BitHighlander
BitHighlander changed the base branch from master to develop March 23, 2026 20:13
@BitHighlander
BitHighlander changed the base branch from develop to master March 23, 2026 20:14
@BitHighlander

Copy link
Copy Markdown
Owner Author

Superseded by combined release PR #13 which includes all 7.14.0 content.

BitHighlander added a commit that referenced this pull request Mar 28, 2026
- C31 test_invalid_bip39_word_rejected removed from SECTIONS — will be
  re-added when PR #3 firmware change lands
- Single-frame tests return None from _pick_best_frame — a single
  frame is always setUp noise (wipe confirm), not test content
BitHighlander added a commit that referenced this pull request Mar 28, 2026
Re-added now that PR #3 firmware fix is landing.
BitHighlander added a commit that referenced this pull request Apr 27, 2026
…ANSPORT, split confirm-flow setUp

Three findings from review of PR #14:

#1 (High) test_dylib_confirm_flow used common.KeepKeyTest.setUp which calls
   wipe_device() — the same path the file's pending regression is for.
   Hangs in setUp can't be classified by xfail or interrupted by
   pytest-timeout, so test_features_round_trip ("just Initialize") was
   actually wipe + Initialize. Refactored to construct
   KeepKeyDebuglinkClient directly in setUp (matching test_dylib_screenshot's
   pattern), moved wipe + load_device into the one pending test.

   Tried the reviewer-suggested @pytest.mark.xfail(strict=True) +
   @pytest.mark.timeout combo. pytest-timeout (both signal and thread
   methods) cannot interrupt the C-level kkemu_poll busy-loop — the
   hang locks up the entire test runner instead of failing the test.
   Switched to @unittest.skip with explicit rationale documenting
   exactly that, plus the promotion path: when firmware lands the
   confirm fix, drop the skip; if a future change makes kkemu_poll
   GIL-friendly, switch back to xfail+timeout.

#2 (Medium) tests/config.py treated any non-empty KK_TRANSPORT as
   "explicit" and skipped HID/WebUSB autodetect, but only "dylib" was
   actually handled. A typo like KK_TRANSPORT=dyllib silently fell
   through to UDP with hardware disabled. Now scoped to a
   _KNOWN_TRANSPORTS set; unsupported values raise at config import,
   surfacing typos at test collection time. Verified end-to-end:
   `KK_TRANSPORT=dyllib pytest test_msg_signtx.py` now errors on
   collection with the typo'd value in the message.

#3 (Medium/Low) DylibTransport.ready_to_read appended raw frame bytes
   to read_buffer but DylibTransport._pump_one stripped the leading '?'
   HID marker first. Inconsistent stripping corrupts multi-frame message
   reassembly: _read_headers can scan a stray '?' from one chunk into
   the middle of contiguous payload bytes from another, decoding the
   wrong message-type / length.

   Centralised the read+strip into a private _poll_and_stash helper
   shared by both ready_to_read (no sleep) and _pump_one (sleeps on
   miss). Now the buffer always contains continuation+payload bytes
   only; the leading '?' is stripped at the single point of stashing.
   Trailing HID padding zeros from short messages are still tolerated
   by _read_headers' magic-character search.

Verified locally:

  KK_TRANSPORT=dylib KK_DYLIB=build-emu/lib/libkkemu.dylib \
    pytest tests/test_dylib_screenshot.py tests/test_dylib_confirm_flow.py
  ================== 5 passed, 1 skipped in 0.15s ==================
BitHighlander added a commit that referenced this pull request Apr 27, 2026
…ANSPORT, split confirm-flow setUp

Three findings from review of PR #14:

#1 (High) test_dylib_confirm_flow used common.KeepKeyTest.setUp which calls
   wipe_device() — the same path the file's pending regression is for.
   Hangs in setUp can't be classified by xfail or interrupted by
   pytest-timeout, so test_features_round_trip ("just Initialize") was
   actually wipe + Initialize. Refactored to construct
   KeepKeyDebuglinkClient directly in setUp (matching test_dylib_screenshot's
   pattern), moved wipe + load_device into the one pending test.

   Tried the reviewer-suggested @pytest.mark.xfail(strict=True) +
   @pytest.mark.timeout combo. pytest-timeout (both signal and thread
   methods) cannot interrupt the C-level kkemu_poll busy-loop — the
   hang locks up the entire test runner instead of failing the test.
   Switched to @unittest.skip with explicit rationale documenting
   exactly that, plus the promotion path: when firmware lands the
   confirm fix, drop the skip; if a future change makes kkemu_poll
   GIL-friendly, switch back to xfail+timeout.

#2 (Medium) tests/config.py treated any non-empty KK_TRANSPORT as
   "explicit" and skipped HID/WebUSB autodetect, but only "dylib" was
   actually handled. A typo like KK_TRANSPORT=dyllib silently fell
   through to UDP with hardware disabled. Now scoped to a
   _KNOWN_TRANSPORTS set; unsupported values raise at config import,
   surfacing typos at test collection time. Verified end-to-end:
   `KK_TRANSPORT=dyllib pytest test_msg_signtx.py` now errors on
   collection with the typo'd value in the message.

#3 (Medium/Low) DylibTransport.ready_to_read appended raw frame bytes
   to read_buffer but DylibTransport._pump_one stripped the leading '?'
   HID marker first. Inconsistent stripping corrupts multi-frame message
   reassembly: _read_headers can scan a stray '?' from one chunk into
   the middle of contiguous payload bytes from another, decoding the
   wrong message-type / length.

   Centralised the read+strip into a private _poll_and_stash helper
   shared by both ready_to_read (no sleep) and _pump_one (sleeps on
   miss). Now the buffer always contains continuation+payload bytes
   only; the leading '?' is stripped at the single point of stashing.
   Trailing HID padding zeros from short messages are still tolerated
   by _read_headers' magic-character search.

Verified locally:

  KK_TRANSPORT=dylib KK_DYLIB=build-emu/lib/libkkemu.dylib \
    pytest tests/test_dylib_screenshot.py tests/test_dylib_confirm_flow.py
  ================== 5 passed, 1 skipped in 0.15s ==================
BitHighlander added a commit that referenced this pull request Apr 29, 2026
…ANSPORT, split confirm-flow setUp

Three findings from review of PR #14:

#1 (High) test_dylib_confirm_flow used common.KeepKeyTest.setUp which calls
   wipe_device() — the same path the file's pending regression is for.
   Hangs in setUp can't be classified by xfail or interrupted by
   pytest-timeout, so test_features_round_trip ("just Initialize") was
   actually wipe + Initialize. Refactored to construct
   KeepKeyDebuglinkClient directly in setUp (matching test_dylib_screenshot's
   pattern), moved wipe + load_device into the one pending test.

   Tried the reviewer-suggested @pytest.mark.xfail(strict=True) +
   @pytest.mark.timeout combo. pytest-timeout (both signal and thread
   methods) cannot interrupt the C-level kkemu_poll busy-loop — the
   hang locks up the entire test runner instead of failing the test.
   Switched to @unittest.skip with explicit rationale documenting
   exactly that, plus the promotion path: when firmware lands the
   confirm fix, drop the skip; if a future change makes kkemu_poll
   GIL-friendly, switch back to xfail+timeout.

#2 (Medium) tests/config.py treated any non-empty KK_TRANSPORT as
   "explicit" and skipped HID/WebUSB autodetect, but only "dylib" was
   actually handled. A typo like KK_TRANSPORT=dyllib silently fell
   through to UDP with hardware disabled. Now scoped to a
   _KNOWN_TRANSPORTS set; unsupported values raise at config import,
   surfacing typos at test collection time. Verified end-to-end:
   `KK_TRANSPORT=dyllib pytest test_msg_signtx.py` now errors on
   collection with the typo'd value in the message.

#3 (Medium/Low) DylibTransport.ready_to_read appended raw frame bytes
   to read_buffer but DylibTransport._pump_one stripped the leading '?'
   HID marker first. Inconsistent stripping corrupts multi-frame message
   reassembly: _read_headers can scan a stray '?' from one chunk into
   the middle of contiguous payload bytes from another, decoding the
   wrong message-type / length.

   Centralised the read+strip into a private _poll_and_stash helper
   shared by both ready_to_read (no sleep) and _pump_one (sleeps on
   miss). Now the buffer always contains continuation+payload bytes
   only; the leading '?' is stripped at the single point of stashing.
   Trailing HID padding zeros from short messages are still tolerated
   by _read_headers' magic-character search.

Verified locally:

  KK_TRANSPORT=dylib KK_DYLIB=build-emu/lib/libkkemu.dylib \
    pytest tests/test_dylib_screenshot.py tests/test_dylib_confirm_flow.py
  ================== 5 passed, 1 skipped in 0.15s ==================
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant