Skip to content

Release 7.14.0 — Solana, TRON, TON#211

Closed
BitHighlander wants to merge 64 commits into
masterfrom
release/7.14.0
Closed

Release 7.14.0 — Solana, TRON, TON#211
BitHighlander wants to merge 64 commits into
masterfrom
release/7.14.0

Conversation

@BitHighlander
Copy link
Copy Markdown
Owner

Release 7.14.0

New Chains

  • Solana: Ed25519/SLIP-10, 37 instruction types, full 44-char address display, AdvancedMode-gated message signing
  • TRON: secp256k1, Base58Check addresses, blind-sign via raw_data
  • TON: Ed25519, v4r2 wallet StateInit, structured field display, memo support

Test Coverage

  • Solana: 13/13 tests (address, signing, token metadata, stake, memo, compute budget)
  • TRON: 6/6 tests (address, blind-sign, rejection)
  • TON: 8/8 tests (address, structured sign, memo, blind-sign, rejection)
  • 100 unit tests (GoogleTest) — all pass
  • OLED screenshots captured for all new chain operations

Infrastructure

  • device-protocol: bf8646b (upstream master — all protos)
  • python-keepkey: 62cc0d8 (expanded tests + report fixes)
  • clang-format pinned to v20 stable
  • FW_VERSION detection for screenshot filter

Upstream PRs (pending human review)

BitHighlander and others added 30 commits March 6, 2026 17:05
Remove QTUM, BNB, ZIL, GTO, IOST, CMT, MCO, and ODEM from tokens.def.

These tokens were listed as ERC-20 entries in the legacy coin table but
their contract addresses no longer exist in the generated uniswap_tokens
table (they migrated to their own L1 chains or were delisted). This
causes Coins.TableSanity unit test to fail because tokenByTicker()
finds them in coins[] but tokenByChainAddress() cannot locate them in
tokens[], returning UnknownToken.

The native chain entries for QTUM, BNB, etc. in coins.def are unaffected
(they have has_contract_address=false).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4-stage fail-fast pipeline: gate (lint, secrets, submodules) → build
(emulator + ARM cross-compile) → test (unit + Python integration) →
publish (manual DockerHub push). Downloadable firmware artifacts with
version-tagged naming. CircleCI config removed.
- Fix gitleaks: use free CLI instead of paid gitleaks-action v2
- Add release.yml: tag-triggered build + draft GitHub Release
- Add release/* and hotfix/* branch patterns to CI triggers
- Add GIT-FLOW.md documenting the branching model
5 benign hits in full-repo scan: U2F dev key, curve25519 README
examples, bootloader public signing keys, and 2014 test wallet.
All reviewed and confirmed non-sensitive.
Adds cppcheck as a Stage 1 GATE job alongside lint-format and secret-scan.
Scans lib/, include/keepkey/, and tools/ with project-aware include paths
and defines. Outputs inline PR annotations and a severity summary table.
Warn-only until existing findings are triaged.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Match CircleCI approach: build emulator from source via docker-compose
instead of pre-built artifact. Restore tokens.def to match upstream
develop after revert.
docker compose up --build firmware-unit leaves the kkemu container
running with dirty emulator state. The subsequent python-keepkey
tests connect to this stale emulator, causing
test_sign_uni_approve_liquidity_ETH to fail with "Signing cancelled
by user". Adding docker compose down between the two runs ensures
python tests get a fresh emulator instance.
actions/checkout defaults to the merge ref for pull_request events,
which fails for fork PRs when the merge commit isn't ready. Use
the PR head SHA directly to avoid auth failures.
CircleCI runs firmware-unit then python-keepkey without tearing down
in between. The docker compose down was destroying the kkemu emulator
and firmware-unit container, making test report extraction fail.
python-keepkey has a nested submodule (ethereum-lists) that contains
the token database used to generate ethereum_tokens.def at build time.
Without --recursive, the token table is empty/partial, causing
Coins.TableSanity and ethereum signing tests to fail.

CircleCI uses --init --recursive globally; match that behavior.
docker-compose v1 (CircleCI) returns all containers with ps -q.
docker compose v2 (GH Actions) only returns running containers.
Need -a flag to include exited containers for docker cp.
Third-party action fails with 401 on fork PRs. Use built-in
actions/upload-artifact instead — test XML is still downloadable.
feat(ci): migrate from CircleCI to GitHub Actions
- Point device-protocol and python-keepkey submodules to upstream master
  (includes BIP-85, Solana, Tron, TON wire IDs and proto definitions)
- Add nanopb .options files for Solana, Tron, TON (field size constraints)
- Add Bip85Mnemonic.mnemonic max_size:241 to messages.options
- Update lib/transport/CMakeLists.txt with new proto sources, options,
  headers, and protoc compilation commands
- Fix CI: use pre-installed clang-format instead of apt-get install
  (eliminates 3-minute timeout on GitHub runners)
- Update Zcash transparent branch ID from Sapling to NU6
chore: update submodules + nanopb options for 7.14.0 proto chains
- actions/checkout v4 → v6
- actions/upload-artifact v4 → v7
- actions/download-artifact v4 → v8
- actions/cache v4 → v5
- docker/setup-buildx-action v3 → v4
- docker/login-action v3 → v4

Node.js 20 actions forced to Node.js 24 starting June 2, 2026
and removed September 16, 2026.
…tions

chore: upgrade GitHub Actions to latest versions
152 files reformatted with `clang-format --style=file` to eliminate
all lint-format CI warnings.
fix: resolve all clang-format CI lint warnings
--output-file writes cppcheck's default format while --template
controls stdout — the two don't combine. When all findings are
suppressed the output file is never created, failing artifact upload.

Drop --output-file and pipe stdout through tee to cppcheck_report.txt
so the file always exists (even if empty) and contains the same
templated annotations used for GitHub PR warnings.
- Remove invalid wildcard suppressions (*:deps/*, *:*.pb.c) that caused
  "Failed to add suppression. No id." — cppcheck never ran
- Simplify unknownMacro suppression (file glob not needed)
- Fix grep patterns to match only ::warning annotation lines, not stray
  cppcheck stderr that polluted the report file
- Use parameter defaults to prevent arithmetic errors on empty grep
cppcheck treats blank lines as suppressions with an empty ID, causing
"Failed to add suppression. No id." — stripped to bare IDs only.
- models.def syntaxError: X-macro pattern cppcheck can't parse
- pb_decode.c memleakOnRealloc: third-party nanopb code

The original wildcard suppressions (*:deps/*, *:*.pb.c) never worked —
cppcheck doesn't accept * as a suppression ID. It errored out on every
CI run before scanning any code. These file-specific suppressions use
valid cppcheck syntax.
- Remove continue-on-error: errors now fail the job
- Suppress known false-positive errors (uninitvar, bufferAccessOutOfBounds,
  subtractPointers, ctunullpointer) with file-specific entries for triage
- Warnings/style/performance findings produce annotations but don't block
- Verified locally: 0 errors, 0 suppression failures
- Add suppressions for errors seen on ubuntu CI cppcheck version:
  syntaxError (global — X-macros in variant.h and models.def),
  preprocessorErrorDirective (pb.h), returnDanglingLifetime (tiny-json.c),
  comparePointers (blupdater — different ID than local subtractPointers)
- Print filtered findings in CI logs for easier debugging
- Verified locally: 0 errors, suppressions clean
fix(ci): ensure cppcheck_report.txt artifact is always created
- Multi-phase CI pipeline with OLED screenshot capture and PDF report generation
- DebugLink canvas→layout bit-packing for 256x64 screenshots (fsm_msg_debug.h, DEBUG_LINK only)
- nanopb DebugLinkState.layout max_size 1024→2048 (full display = 2048 bytes at 1bpp)
- Docker emulator healthcheck (/health endpoint + service_healthy condition)
- Fail-fast gates: CI errors on zero screenshots, conftest hook enforces capture
- Zoo screenshot tooling (capture, report, smoke test, emulator wait)
- Version bump 7.10.0→7.14.0 (release target metadata)
- Pin python-keepkey to screenshot/report-enabled version with requires_message() gating

19 files changed, zero production firmware code modified.
BitHighlander and others added 28 commits April 1, 2026 23:55
Remove every "cheat green" pattern from the CI pipeline:

GATE stage now actually gates:
- lint-format: remove continue-on-error, exit 1 on any formatting diff
- static-analysis: --error-exitcode=1, fail on ANY cppcheck finding
  (zero-warning policy — use .cppcheck-suppressions for intentional items)
- Build and test stages now depend on ALL gate jobs (lint + cppcheck +
  submodules + secrets), not just submodules + secrets

Integration tests now fail honestly:
- Remove `set +e` that swallowed docker compose failures
- Use `--exit-code-from` to capture real container exit codes
- Remove fragile status-file-based pass/fail (defaulted to "1" on
  missing file, which could mask the real failure mode)

This PR WILL go red on branches that have unfixed lint/cppcheck warnings.
That is intentional — merge keepkey#407 (cppcheck fixes) first to go green.
11 files had formatting diffs introduced by the static analysis
fixes in keepkey#407. Now clean against .clang-format.
fix(ci): enforce fail-fast — no more silent passes
Submodule was pinned to orphan commit 79d467d1 (unreachable from any
branch in keepkey/python-keepkey). Update to current master (8fbef437,
merge of fix/hotfixes-714).
…ule-pin

fix: pin deps/python-keepkey to upstream master HEAD
Firmware only matched legacy deposit() selector (0x1fece7b4). All
modern THORChain routers use depositWithExpiry() (0x44bc937b), causing
every EVM THORChain swap to require blind signing.

- thortx.h: add THOR_SELECTOR_DEPOSIT and THOR_SELECTOR_DEPOSIT_WITH_EXPIRY
- thortx.c: match either selector with correct memo offset per variant
- deps/python-keepkey: pin to upstream master HEAD (8fbef437)
BIP-44 coin type 191 (0x800000bf), address version 45, segwit
enabled with bech32 prefix "lynx", taproot support.
When decoding a oneof submessage field, only memset to zero when
switching to a different union variant. Previously the tag was set
before the zero-check, so stale callback pointers from the previous
union field could persist, causing memory leaks or use-after-free.

Backport of nanopb/nanopb@4fe23595.
Updated Lynx entry to use 'Lynx Signed Message' instead of 'Bitcoin Signed Message'.
…clean

fix: nanopb oneof memory leak (backport 4fe23595)
…Expiry-upstream

fix: recognize modern THORChain depositWithExpiry selector (0x44bc937b)
Pin clang-format to version 20 (latest LLVM stable release) instead of
unpinned nightly. The nightly repo rolls forward (currently v23) and
different versions produce different formatting, causing spurious lint
failures on feature branches.

Also fixes the one file (zxappliquid.c) that differed between v20 and v23.
Bump device-protocol submodule from b07589f to bf8646b (upstream master).
This includes PRs #100 (7.14.0 protos) and #101 (ZcashDisplayAddress).

Add nanopb options entries for new proto fields to prevent pb_callback_t:
- messages-ethereum.options: EthereumTxMetadata, EthereumMetadataAck
- messages-solana.options: SolanaTokenInfo, SolanaSignTx.token_info
- messages-ton.options: TonSignTx.memo
- messages-tron.options: TronTransferContract, TronTriggerSmartContract, etc.
chore: bump device-protocol to master + update nanopb options
Without this, the screenshot filter defaults to 7.10.0 when FW_VERSION
is not in the environment. This excludes all 7.14.0+ chains (Solana,
TRON, TON, Zcash) from OLED screenshot capture in CI Phase 1.

Now reads the version from CMakeLists.txt inside the Docker container
before running the filter, so new chain screenshots are captured.
fix(ci): detect FW_VERSION for OLED screenshot capture
TRON: secp256k1 blind-signing with Base58Check addresses (T prefix).
TON: Ed25519 with v4r2 wallet StateInit, clear-sign + blind-sign modes.

New files:
- tron.h/c: address derivation, amount formatting, signing
- ton.h/c: v4r2 address generation, cell hashing, signing
- fsm_msg_tron.h: GetAddress, SignTx handlers
- fsm_msg_ton.h: GetAddress, SignTx handlers
- messages-tron.options, messages-ton.options: nanopb constraints

Integration:
- fsm.c: includes + handler linkage
- fsm.h: function declarations
- messagemap.def: wire IDs 1400-1403 (TRON), 1500-1503 (TON)
- interface.h: messages-tron.pb.h, messages-ton.pb.h includes
- CMakeLists.txt: tron.c, ton.c added to build

Submodules:
- device-protocol: 18bb4a7 (upstream master)
- python-keepkey: 3d36e92 (upstream master)
Ed25519/SLIP-10 address derivation with 35 instruction types parsed
for clear-sign display. Blind-sign gated by AdvancedMode policy.
Message signing gated by AdvancedMode (no domain separation).

New files:
- solana.h/c: tx parser, signing, amount/token formatting
- fsm_msg_solana.h: GetAddress, SignTx, SignMessage handlers
- solana.cpp: 14 unit tests for parser edge cases
- messages-solana.options: nanopb field constraints

Integration:
- fsm.c: includes + handler linkage
- fsm.h: function declarations
- messagemap.def: wire IDs 750-755
- interface.h: messages-solana.pb.h include
- CMakeLists.txt: solana.c added to build

Submodules:
- device-protocol: 18bb4a7 (upstream master)
- python-keepkey: 3d36e92 (upstream master)
Define SOL_SYS_*, SOL_TOKEN_*, SOL_STAKE_*, SOL_VOTE_*, SOL_CB_*
constants for all instruction indices. Also defines SOL_MAX_ACCOUNTS,
SOL_MAX_INSTRUCTIONS, SOL_LAMPORTS_DIVISOR, SOL_VERSION_FLAG/MASK,
and compact-u16 encoding constants for readability.
Do not change deps/crypto/trezor-firmware or deps/python-keepkey
pinning in this feature branch.
feat: Solana support (GetAddress, SignTx, SignMessage)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants