Skip to content

fix: verify native release build ids#1106

Open
ovitrif wants to merge 1 commit into
masterfrom
ovi/fix-native-symbol-build-ids
Open

fix: verify native release build ids#1106
ovitrif wants to merge 1 commit into
masterfrom
ovi/fix-native-symbol-build-ids

Conversation

@ovitrif

@ovitrif ovitrif commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Fixes #1104

Implements the Android consumer portion of #1105.

This PR is blocked until synonymdev/ldk-node#98, synonymdev/bitkit-core#131, synonymdev/vss-rust-client-ffi#19, and pubky/paykit-rs#124 receive human approval, merge, and publish their versioned artifacts.

Description

  • consumes Paykit's native-debug-symbols classifier and adds libpaykit.so to the required release symbol set
  • validates GNU build-ID presence and packaged-to-symbol parity for libldk_node.so, libbitkitcore.so, libvss_rust_client_ffi.so, and libpaykit.so across both release ABIs
  • validates the final AAB and universal APK before creating the native debug-symbol archive
  • requires full DWARF metadata in every archived symbol library and fails the release path on absent or mismatched artifacts
  • configures the internal release workflow to produce both the APK and AAB inputs required by the parity gate
  • pins the locally integrated producer versions: LDK 0.7.0-rc.58, bitkit-core 0.4.4, VSS 0.5.21, and Paykit 0.1.1

Preview

N/A — release artifact validation only.

QA Notes

Manual Tests

  • Published all four producers to a task-local Maven repository and built Bitkit Android exclusively against those artifacts without changing shared Maven state.
  • Generated native-debug-symbols-187.zip, the matching mainnet release AAB, and the universal release APK.
  • Independently inspected every packaged and symbol library with NDK llvm-readelf -n; all eight packaged libraries matched their full-DWARF symbol counterparts.
  • Installed and launched the debug app on a Pixel 10 Pro and a 16 KB-page Android emulator.
  • (after merge) Run the internal release workflow and verify that AAB/APK parity validation completes before symbol upload.

Automated Checks

  • just compile
  • just test
  • just lint (passes with existing warnings)
  • just release
  • NativeReleaseConfigTest.kt — 7 passed
  • ./scripts/test-create-native-debug-symbols.sh
  • shellcheck scripts/create-native-debug-symbols.sh scripts/test-create-native-debug-symbols.sh
  • actionlint .github/workflows/release-internal.yml
  • final build-ID parity passed for arm64-v8a and x86_64 across all four native libraries

@greptile-apps

greptile-apps Bot commented Jul 24, 2026

Copy link
Copy Markdown

Greptile Summary

Native release generation now verifies full-DWARF symbol archives and GNU build-ID parity against both final app artifacts.

  • Adds Paykit to the required native symbol set.
  • Validates symbols for all configured release ABIs and four Rust libraries.
  • Builds both the APK and AAB in the internal release workflow.
  • Pins compatible LDK, bitkit-core, VSS, and Paykit producer versions.
  • Configures explicit LDK additional-wallet scan defaults and expands release-validation tests.

Confidence Score: 5/5

The PR appears safe to merge, with the release artifact paths, configured ABIs, symbol inputs, and build-ID validation aligned across current release callers.

The known release paths build both required artifacts before validation, use filenames derived from the same version code, and validate the same arm64-v8a and armeabi-v7a ABI set configured for release builds; no actionable changed-code failure remains.

Important Files Changed

Filename Overview
scripts/create-native-debug-symbols.sh Adds full-DWARF and GNU build-ID validation against correctly named AAB and universal APK artifacts for the configured release ABIs.
scripts/test-create-native-debug-symbols.sh Adds isolated fixtures covering absent GNU notes, mismatched packaged IDs, and successful parity across both app artifacts.
.github/workflows/release-internal.yml Builds both release artifact formats before resolving and validating native symbols.
app/build.gradle.kts Resolves Paykit’s native debug-symbol classifier alongside the other Rust producers.
app/src/main/java/to/bitkit/services/LightningService.kt Supplies explicit LDK defaults for additional-wallet full-scan batch size and stop gap.
gradle/libs.versions.toml Updates the four native producer dependencies to versions that publish compatible symbol artifacts.
app/src/test/java/to/bitkit/build/NativeReleaseConfigTest.kt Extends release configuration coverage for all symbol producers, app-artifact parity, and executable script fixtures.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    A[Build release APK and AAB] --> B[Resolve producer symbol archives]
    B --> C[Normalize symbols by ABI and library]
    C --> D{Full DWARF and GNU build IDs present?}
    D -- No --> E[Fail release]
    D -- Yes --> F{IDs match AAB and universal APK?}
    F -- No --> E
    F -- Yes --> G[Create native debug-symbol archive]
Loading

Reviews (1): Last reviewed commit: "fix: verify native symbol build ids" | Re-trigger Greptile

@coreyphillips coreyphillips left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script itself holds up well. I traced it against dash, macOS sh, NDK 28 llvm-readelf and Info-ZIP, and these are all correct and need no changes:

  • build_id() awk parse. Real llvm-readelf -n puts the NT_GNU_BUILD_ID marker and the hash on separate lines, so $3 on the Build ID: line is the hash and the next never skips it. binutils readelf uses the identical two-line form, so the GNU fallback in find_readelf parses the same.
  • require_build_id's exit 1 inside a command substitution. POSIX gives an assignment the status of its last command substitution, and dash propagates it under set -e. A probe where every packaged lib lacks NT_GNU_BUILD_ID aborts with status 1 rather than passing vacuously. validate_symbol_tree also always runs first at both call sites and calls require_build_id in the current shell, so the symbol side can never be empty when parity runs.
  • llvm-strip preserves .note.gnu.build-id, so packaged-to-symbol parity is satisfiable in principle.
  • The fixture's trap re-installation and temp-dir cleanup, and the hardcoded AAB name against the FinalizeBundleTask rename block.
  • The LightningService change is forced, not scope creep: ElectrumSyncConfig gained additional_wallet_full_scan_batch_size and additional_wallet_full_scan_stop_gap in ldk-node rc.55 with no UDL defaults, so the generated Kotlin constructor requires both. The /** LDK's default */ KDoc is literally accurate against src/config.rs (5 and 20). Worth saying so in the PR body, since as written a reader cannot tell a forced binding update from an unrelated wallet-config change.

Blocking status is exactly as the body says. All four upstream PRs are still open and none of the four pinned versions are published (latest: ldk-node v0.7.0-rc.57, bitkit-core v0.4.3, vss-rust-client-ffi v0.5.20, paykit v0.1.0-rc39). That fully explains the red CI and is not a defect here.

Five things to resolve before this lands.

1. The paykit line needs a decision

0.1.1 is not rc33 plus six RCs. pubky/paykit-rs#124 targets release/0.1.1, and the CHANGELOG on that branch goes straight from [Unreleased] to [0.1.0-rc33], so rc34 through rc39 are not in it.

Meanwhile four open PRs here are on the newer line: codex/paykit-incoming-payment-requests-rc39 and codex/batch-paykit-contact-cleanup on rc39, codex/970-pubky-paykit-ui-parity and codex/paykit-watch-only-accounts on rc37. rc37 is breaking (session signup/signin/auth require the receiver Noise key explicitly) and rc38/rc39 are breaking (no implicit private-to-public fallback, callers choose the payment mode).

Whichever merges second loses something: keep 0.1.1 and the rc39 call sites no longer exist, keep 0.1.0-rc39 and create-native-debug-symbols.sh aborts at require_build_id with no NT_GNU_BUILD_ID for libpaykit.so. Can we get a build-ID-enabled release cut on top of rc39, or land this with paykit left at rc33 and add libpaykit.so to required_libs in a follow-up once the lines converge?

2. ADDITIONAL_WALLET_FULL_SCAN_STOP_GAP = 20u contradicts the derived-account branches

The four in-flight branches carrying the watch-only work all set 100/1000 for these. If one of them rebases onto master after this lands, the KDoc makes 20 look authoritative, and a Trezor account whose owner previously received beyond 20 consecutive unused addresses would come back with a missing balance.

Was 5/20 a deliberate divergence from the 100/1000 those branches already agreed on, or just preserving pre-rc.55 behavior? If the latter, worth either matching them or leaving a comment tying the value to that work so a later rebase does not silently keep 20.

3. The ldk-node jump needs wallet QA

rc.52 to rc.58 crosses six release candidates. rc.54's notes cover "corrected RBF input/change selection, replacement fee enforcement, foreign-input weight estimation, and reserve calculations across aggregated wallets", which touches boost and coin selection directly. rc.55/rc.56 add rolling receive-address lookahead for derived accounts.

The QA notes here are all symbol and build checks plus a launch on device. Could you add boost, send with anchor reserves, and restore-from-seed balance on regtest, or split the ldk-node bump into its own PR so it gets reviewed as a wallet change rather than as tooling?

4. QA note names an ABI the gate does not check

The notes end with "final build-ID parity passed for arm64-v8a and x86_64". validate_packaged_build_id_parity loops arm64-v8a armeabi-v7a, and the release abiFilters are armeabi-v7a plus arm64-v8a (x86_64 is debug only), so x86_64 is neither packaged nor inspected, and armeabi-v7a is not mentioned. Since CI cannot run here, the QA notes are the only evidence the gate was exercised end to end, and armeabi-v7a is the ABI most likely to diverge because it is a separate toolchain.

5. Changelog fragment

Native build IDs are release tooling rather than something a user observes, while the parts of this PR that are user facing (ldk-node rc.54's RBF and coin-selection corrections, bitkit-core 0.4.1 to 0.4.4) are not mentioned. Either drop the fragment or rewrite it to cover the user-visible change.

Minor, on naming: every other fragment in changelog.d/next/ is keyed to the PR number, including 1091.fixed.md which fixes issue #1034. 1104.fixed.md is the only one keyed to an issue.

Conflicts with #1107

git merge-tree gives conflicts in scripts/create-native-debug-symbols.sh, app/src/test/java/to/bitkit/build/NativeReleaseConfigTest.kt and gradle/libs.versions.toml. release-internal.yml and app/build.gradle.kts auto-merge cleanly.

The dangerous hunk: this PR adds libpaykit.so to required_libs, #1107 splits the same line into dependency_required_libs plus application_required_libs. Taking #1107's side drops libpaykit.so from the release symbol gate silently, and NativeReleaseConfigTest then fails whichever side is taken, where the least-effort green fix is to delete libpaykit.so from the script and cement the gap. Correct resolution:

dependency_symbols_dir=${NATIVE_SYMBOLS_DEPENDENCY_DIR:-app/build/intermediates/native-debug-symbol-artifacts}
dependency_required_libs="libbitkitcore.so libldk_node.so libpaykit.so libvss_rust_client_ffi.so"
application_required_libs="libimage_processing_util_jni.so libsurface_util_jni.so libandroidx.graphics.path.so"
required_libs="$dependency_required_libs $application_required_libs"

with the test assertion updated to match and both new @Test methods kept.

Also worth noting: #1107's check-16kb-compat.sh validates every .so in the final artifacts, including all four Rust libraries this PR bumps, and that gate runs only on release paths, never on PRs. I checked the current versions (ldk-node rc.52, paykit rc33, vss-client 0.5.20, bitkit-core) and all pass on both ABIs, but this PR replaces all four. Suggest running llvm-readelf -W -l and llvm-readelf -n over the jni/arm64-v8a and jni/armeabi-v7a .so files in the four new AARs once they publish, and pasting the results into the QA notes, so an unaligned or build-ID-less lib is caught before a release rather than during one.

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.

fix: verify native symbol build IDs

2 participants