diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c28379a1..1079fc243 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.7.0-rc.57 (Synonym Fork) +# 0.7.0-rc.58 (Synonym Fork) ## Bug Fixes @@ -68,6 +68,8 @@ ## Synonym Fork Additions +- Added stable GNU build IDs to every Android ABI and verified that packaged + libraries match their unstripped native debug symbols. - Added rolling lookahead for derived on-chain accounts after their initial full scan. - Added configurable Electrum batch size and stop gap for full scans of non-primary on-chain wallets, while preserving the existing primary-wallet behavior and defaults. diff --git a/Cargo.toml b/Cargo.toml index 3314930f6..c79af3b88 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ exclude = ["bindings/uniffi-bindgen"] [package] name = "ldk-node" -version = "0.7.0-rc.57" +version = "0.7.0-rc.58" authors = ["Elias Rohrer "] homepage = "https://lightningdevkit.org/" license = "MIT OR Apache-2.0" diff --git a/Package.swift b/Package.swift index d5ece4876..59c8a6c3d 100644 --- a/Package.swift +++ b/Package.swift @@ -3,8 +3,8 @@ import PackageDescription -let tag = "v0.7.0-rc.57" -let checksum = "930c0eb9b043a23cd519e1dec4697f51f9c8ad669a303f18da902b5943840d00" +let tag = "v0.7.0-rc.58" +let checksum = "caca6b4ef9df81cd84279438894aa37116c69fd4b86e3070722c824e7af5f634" let url = "https://github.com/synonymdev/ldk-node/releases/download/\(tag)/LDKNodeFFI.xcframework.zip" let package = Package( diff --git a/bindings/kotlin/ldk-node-android/gradle.properties b/bindings/kotlin/ldk-node-android/gradle.properties index 983dcbfb4..590b5081e 100644 --- a/bindings/kotlin/ldk-node-android/gradle.properties +++ b/bindings/kotlin/ldk-node-android/gradle.properties @@ -3,4 +3,4 @@ android.useAndroidX=true android.enableJetifier=true kotlin.code.style=official group=com.synonym -version=0.7.0-rc.57 +version=0.7.0-rc.58 diff --git a/bindings/kotlin/ldk-node-android/lib/build.gradle.kts b/bindings/kotlin/ldk-node-android/lib/build.gradle.kts index 8cff608b3..4e8aaf1b7 100644 --- a/bindings/kotlin/ldk-node-android/lib/build.gradle.kts +++ b/bindings/kotlin/ldk-node-android/lib/build.gradle.kts @@ -1,5 +1,6 @@ import java.io.ByteArrayOutputStream import java.io.File +import java.util.zip.ZipFile plugins { id("com.android.library") @@ -105,6 +106,19 @@ fun Project.runReadelf(readelf: String, vararg args: String): Pair return result.exitValue to stdout.toString().ifBlank { stderr.toString() } } +fun Project.gnuBuildId(readelf: String, lib: File): String { + val (notesExit, notes) = runReadelf(readelf, "-n", lib.absolutePath) + val buildId = Regex("""(?s)NT_GNU_BUILD_ID.*?Build ID:\s*([0-9a-fA-F]+)""") + .find(notes) + ?.groupValues + ?.get(1) + if (notesExit != 0 || buildId.isNullOrEmpty()) { + throw GradleException("Android native library has no NT_GNU_BUILD_ID: '${lib.path}'") + } + + return buildId +} + fun String.parseElfAlignment(): Long { return if (startsWith("0x")) { removePrefix("0x").toLong(16) @@ -115,12 +129,11 @@ fun String.parseElfAlignment(): Long { val validateReleaseNativeLibraries by tasks.registering { group = "verification" - description = "Validates release JNI libraries are stripped and keep 16 KB LOAD alignment." + description = "Validates release JNI libraries are stripped, 16 KB aligned, and carry GNU build IDs." doLast { val readelf = findReadelf() val loadAlignmentRegex = Regex("""^\s*LOAD\s+.*\s+(0x[0-9a-fA-F]+|\d+)\s*$""") - androidNativeAbis.forEach { abi -> val lib = layout.projectDirectory.file("src/main/jniLibs/$abi/libldk_node.so").asFile if (!lib.isFile) { @@ -135,6 +148,8 @@ val validateReleaseNativeLibraries by tasks.registering { throw GradleException("Android release native library still contains .debug_* sections: '${lib.path}'") } + gnuBuildId(readelf, lib) + val wideHeaders = runReadelf(readelf, "-W", "-l", lib.absolutePath) val headers = if (wideHeaders.first == 0) { wideHeaders.second @@ -158,10 +173,76 @@ val validateReleaseNativeLibraries by tasks.registering { } } -tasks.matching { it.name == "bundleReleaseAar" || it.name.startsWith("publish") }.configureEach { +val validatePublishedNativeArtifacts by tasks.registering { + group = "verification" + description = "Validates final AAR and full-DWARF symbol build IDs match for every Android ABI." + dependsOn("bundleReleaseAar", validateReleaseNativeLibraries) + + doLast { + val readelf = findReadelf() + val aar = layout.buildDirectory.dir("outputs/aar").get().asFile + .listFiles() + ?.singleOrNull { it.name.endsWith("-release.aar") } + ?: throw GradleException("Exactly one release AAR is required for native build-ID validation") + val symbolArchive = rootProject.layout.projectDirectory.file("native-debug-symbols.zip").asFile + if (!symbolArchive.isFile) { + throw GradleException("Native debug symbol archive missing at '${symbolArchive.path}'") + } + + val validationDir = layout.buildDirectory.dir("tmp/validatePublishedNativeArtifacts").get().asFile + validationDir.deleteRecursively() + validationDir.mkdirs() + + fun extract(zip: ZipFile, entryName: String, output: File): File { + val entry = zip.getEntry(entryName) + ?: throw GradleException("Native artifact entry missing: '$entryName'") + output.parentFile.mkdirs() + zip.getInputStream(entry).use { input -> + output.outputStream().use { input.copyTo(it) } + } + return output + } + + ZipFile(aar).use { aarZip -> + ZipFile(symbolArchive).use { symbolZip -> + androidNativeAbis.forEach { abi -> + val packaged = extract( + aarZip, + "jni/$abi/libldk_node.so", + File(validationDir, "aar/$abi/libldk_node.so") + ) + val symbols = extract( + symbolZip, + "$abi/libldk_node.so", + File(validationDir, "symbols/$abi/libldk_node.so") + ) + val (sectionsExit, sections) = runReadelf(readelf, "-S", symbols.absolutePath) + if (sectionsExit != 0 || !sections.contains(".debug_info")) { + throw GradleException("Full DWARF .debug_info missing for '$abi/libldk_node.so'") + } + + val packagedBuildId = gnuBuildId(readelf, packaged) + val symbolBuildId = gnuBuildId(readelf, symbols) + if (packagedBuildId != symbolBuildId) { + throw GradleException( + "Native build ID mismatch for '$abi/libldk_node.so': " + + "aar=$packagedBuildId symbols=$symbolBuildId" + ) + } + } + } + } + } +} + +tasks.matching { it.name == "bundleReleaseAar" }.configureEach { dependsOn(validateReleaseNativeLibraries) } +tasks.matching { it.name == "build" || it.name == "check" || it.name.startsWith("publish") }.configureEach { + dependsOn(validatePublishedNativeArtifacts) +} + afterEvaluate { publishing { publications { diff --git a/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/arm64-v8a/libldk_node.so b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/arm64-v8a/libldk_node.so index f656984b3..ebe0d3727 100755 Binary files a/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/arm64-v8a/libldk_node.so and b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/arm64-v8a/libldk_node.so differ diff --git a/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/armeabi-v7a/libldk_node.so b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/armeabi-v7a/libldk_node.so index 4cc2e630d..76aba6141 100755 Binary files a/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/armeabi-v7a/libldk_node.so and b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/armeabi-v7a/libldk_node.so differ diff --git a/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/x86_64/libldk_node.so b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/x86_64/libldk_node.so index 6a7ddbfce..17611733c 100755 Binary files a/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/x86_64/libldk_node.so and b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/x86_64/libldk_node.so differ diff --git a/bindings/kotlin/ldk-node-jvm/gradle.properties b/bindings/kotlin/ldk-node-jvm/gradle.properties index bb2814b13..962764ca0 100644 --- a/bindings/kotlin/ldk-node-jvm/gradle.properties +++ b/bindings/kotlin/ldk-node-jvm/gradle.properties @@ -1,4 +1,4 @@ org.gradle.jvmargs=-Xmx1536m kotlin.code.style=official group=com.synonym -version=0.7.0-rc.57 +version=0.7.0-rc.58 diff --git a/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-aarch64/libldk_node.dylib b/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-aarch64/libldk_node.dylib index 6040b871f..48d7b19ae 100644 Binary files a/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-aarch64/libldk_node.dylib and b/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-aarch64/libldk_node.dylib differ diff --git a/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-x86-64/libldk_node.dylib b/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-x86-64/libldk_node.dylib index a816aae96..fdd2c6c3b 100644 Binary files a/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-x86-64/libldk_node.dylib and b/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-x86-64/libldk_node.dylib differ diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml index 14939bd6f..39f8cbf70 100644 --- a/bindings/python/pyproject.toml +++ b/bindings/python/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "ldk_node" -version = "0.7.0-rc.57" +version = "0.7.0-rc.58" authors = [ { name="Elias Rohrer", email="dev@tnull.de" }, ] diff --git a/scripts/uniffi_bindgen_generate_kotlin_android.sh b/scripts/uniffi_bindgen_generate_kotlin_android.sh index 2612fb073..1257097a9 100755 --- a/scripts/uniffi_bindgen_generate_kotlin_android.sh +++ b/scripts/uniffi_bindgen_generate_kotlin_android.sh @@ -61,7 +61,7 @@ echo "Building for Android architectures..." JNI_LIB_DIR="$ANDROID_LIB_DIR/lib/src/main/jniLibs" export CARGO_PROFILE_RELEASE_SMALLER_STRIP=false export CARGO_PROFILE_RELEASE_SMALLER_DEBUG=2 -export RUSTFLAGS="-C link-args=-Wl,-z,max-page-size=16384,-z,common-page-size=16384" +export RUSTFLAGS="-C link-arg=-Wl,--build-id=sha1 -C link-args=-Wl,-z,max-page-size=16384,-z,common-page-size=16384" export CFLAGS="-D__ANDROID_MIN_SDK_VERSION__=21" find_readelf() { @@ -130,6 +130,28 @@ has_dwarf_sections() { "$READELF_BIN" -S "$1" | grep -E '\.debug_' >/dev/null } +android_build_id() { + readelf_notes=$("$READELF_BIN" -n "$1") || { + echo "Error: Unable to inspect Android native library notes: $1" >&2 + return 1 + } + + printf '%s\n' "$readelf_notes" | awk ' + /NT_GNU_BUILD_ID/ { found_gnu_build_id = 1; next } + found_gnu_build_id && /Build ID:/ { print $3; exit } + ' +} + +require_android_build_id() { + build_id=$(android_build_id "$1") + if [ -z "$build_id" ]; then + echo "Error: Android native library has no NT_GNU_BUILD_ID: $1" >&2 + exit 1 + fi + + printf '%s\n' "$build_id" +} + readelf_program_headers() { if "$READELF_BIN" -W -l "$1" >/dev/null 2>&1; then "$READELF_BIN" -W -l "$1" @@ -160,6 +182,8 @@ EOF validate_android_library() { lib="$1" + require_android_build_id "$lib" >/dev/null + if ! has_dwarf_debug_metadata "$lib"; then echo "Error: Android native library has no .debug_info DWARF metadata: $lib" exit 1 @@ -174,6 +198,8 @@ validate_android_library() { validate_stripped_android_library() { lib="$1" + require_android_build_id "$lib" >/dev/null + if has_dwarf_sections "$lib"; then echo "Error: Android release native library still contains .debug_* sections: $lib" exit 1 @@ -249,17 +275,36 @@ validate_android_aar_symbols() { fi tmp_dir=$(mktemp -d) - unzip -q "$aar" -d "$tmp_dir" + aar_dir="$tmp_dir/aar" + symbols_dir="$tmp_dir/symbols" + mkdir -p "$aar_dir" "$symbols_dir" + unzip -q "$aar" -d "$aar_dir" + unzip -q "$NATIVE_DEBUG_SYMBOLS_ZIP" -d "$symbols_dir" for abi in armeabi-v7a arm64-v8a x86_64; do - lib="$tmp_dir/jni/$abi/libldk_node.so" - if [ ! -f "$lib" ]; then - echo "Error: Android release AAR native library missing at $lib" + packaged_lib="$aar_dir/jni/$abi/libldk_node.so" + symbol_lib="$symbols_dir/$abi/libldk_node.so" + if [ ! -f "$packaged_lib" ]; then + echo "Error: Android release AAR native library missing at $packaged_lib" + rm -rf "$tmp_dir" + exit 1 + fi + if [ ! -f "$symbol_lib" ]; then + echo "Error: Android native debug symbol library missing at $symbol_lib" rm -rf "$tmp_dir" exit 1 fi - validate_stripped_android_library "$lib" + validate_stripped_android_library "$packaged_lib" + validate_android_library "$symbol_lib" + + packaged_build_id=$(require_android_build_id "$packaged_lib") + symbol_build_id=$(require_android_build_id "$symbol_lib") + if [ "$packaged_build_id" != "$symbol_build_id" ]; then + echo "Error: Android build ID mismatch for $abi/libldk_node.so: packaged=$packaged_build_id symbols=$symbol_build_id" + rm -rf "$tmp_dir" + exit 1 + fi done rm -rf "$tmp_dir" @@ -310,7 +355,8 @@ echo "Version synced: $CARGO_VERSION" # Verify android library publish task graph echo "Testing android library publish to Maven Local..." -$ANDROID_LIB_DIR/gradlew --project-dir "$ANDROID_LIB_DIR" clean publishToMavenLocal +$ANDROID_LIB_DIR/gradlew --project-dir "$ANDROID_LIB_DIR" clean bundleReleaseAar validate_android_aar_symbols +$ANDROID_LIB_DIR/gradlew --project-dir "$ANDROID_LIB_DIR" publishToMavenLocal echo "Android build process completed successfully!"