Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 171 additions & 0 deletions .github/workflows/build-and-verify-alignment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
name: Build and Verify 16KB Page Size Alignment

on:
push:
branches: [ master, main, develop ]
pull_request:
branches: [ master, main, develop ]

jobs:
build-and-verify:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'

- name: Setup Android SDK
uses: android-actions/setup-android@v3

- name: Cache Gradle packages
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-

- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Build with Gradle
run: ./gradlew build

- name: Verify 16KB Page Size Alignment
run: |
echo "🔍 Checking 16KB page size alignment of 64-bit native libraries..."

# Function to check alignment of a shared library
check_alignment() {
local lib_path="$1"
local lib_name=$(basename "$lib_path")

echo "Checking $lib_name..."

# Use llvm-readelf from NDK to check alignment
local ndk_path="$ANDROID_NDK_ROOT"
local readelf="$ndk_path/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-readelf"

if [ ! -f "$readelf" ]; then
echo "❌ Error: llvm-readelf not found at $readelf"
return 1
fi

# Check LOAD segments alignment
local alignments=$($readelf -l "$lib_path" | grep "LOAD" | awk '{print $NF}')

local all_aligned=true
for alignment in $alignments; do
# Convert hex to decimal
local decimal_alignment=$((alignment))
local kb_alignment=$((decimal_alignment / 1024))

echo " Segment alignment: $alignment ($decimal_alignment bytes = ${kb_alignment}KB)"

if [ $decimal_alignment -ne 16384 ]; then
echo " ❌ Not 16KB aligned (expected 0x4000 = 16384 bytes)"
all_aligned=false
else
echo " ✅ 16KB aligned"
fi
done

if [ "$all_aligned" = true ]; then
echo "✅ $lib_name is properly 16KB aligned"
return 0
else
echo "❌ $lib_name has incorrect alignment"
return 1
fi
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: False positive if no LOAD segments found.

If readelf -l produces no output matching "LOAD" (line 65), the for loop at line 68 never executes, leaving all_aligned=true (initialized at line 67). The function then returns 0, incorrectly reporting success.

This creates a false positive if:

  • readelf output format is unexpected
  • grep "LOAD" matches nothing due to malformed library or parsing issue
  • readelf itself fails silently

Apply this fix to detect missing or empty results:

   # Check LOAD segments alignment
   local alignments=$($readelf -l "$lib_path" | grep "LOAD" | awk '{print $NF}')

-  local all_aligned=true
+  if [ -z "$alignments" ]; then
+    echo "  ❌ No LOAD segments found (unable to verify alignment)"
+    return 1
+  fi
+
+  local all_aligned=true
   for alignment in $alignments; do

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
.github/workflows/build-and-verify-alignment.yml around lines 67 to 90: the loop
assumes there are LOAD segments and will report success when none are found;
detect empty or missing readelf results and treat that as a failure by checking
whether the alignments variable is empty (or readelf returned nothing) before
looping and set all_aligned=false / return non‑zero if so; implement an explicit
test after capturing alignments to bail out with an error message when no LOAD
entries were found (or when readelf returns non‑zero) so the job does not
produce a false positive.


# Find all .so files in build outputs (64-bit architectures only)
echo "Finding 64-bit native libraries in build outputs..."
so_files=$(find . -path "*/build/intermediates/cxx/*/obj/*/*.so" -type f | grep -E "(Release|RelWithDebInfo)" | grep -E "(arm64-v8a|x86_64)" | head -20)

if [ -z "$so_files" ]; then
echo "❌ No native libraries found in build outputs"
exit 1
fi

echo "Found native libraries:"
echo "$so_files"
echo

# Check alignment for each library
all_libs_aligned=true
for so_file in $so_files; do
if ! check_alignment "$so_file"; then
all_libs_aligned=false
fi
echo
done

# Summary
echo "📊 Alignment Verification Summary:"
if [ "$all_libs_aligned" = true ]; then
echo "🎉 All native libraries are properly 16KB aligned!"
echo "✅ This build is compatible with 16KB page size devices"
else
echo "❌ Some libraries are not properly aligned"
echo "💡 Ensure you're using Android Gradle Plugin 8.5.1+ and target SDK 35+"
exit 1
fi

- name: Verify AAR Contents
run: |
echo "🔍 Verifying AAR files contain native libraries..."

# Find AAR files
aar_files=$(find . -name "*.aar" -path "*/build/outputs/aar/*" -type f)

if [ -z "$aar_files" ]; then
echo "❌ No AAR files found"
exit 1
fi

echo "Found AAR files:"
for aar in $aar_files; do
echo "📦 $(basename $aar)"

# Check if AAR contains native libraries
native_libs=$(unzip -l "$aar" | grep -E "jni/.*\.so$" | wc -l)

if [ $native_libs -gt 0 ]; then
echo " ✅ Contains $native_libs native libraries"
echo " 📋 Native library details:"
unzip -l "$aar" | grep -E "jni/.*\.so$" | awk '{print " " $4}'
else
echo " ℹ️ No native libraries (library may be pure Java/Kotlin)"
fi
echo
done

- name: Upload build artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: build-outputs
path: |
**/build/outputs/aar/*.aar
**/build/intermediates/cxx/*/obj/*/*.so
retention-days: 7

- name: Upload lint reports
uses: actions/upload-artifact@v4
if: always()
with:
name: lint-reports
path: |
**/build/reports/lint-results-*.html
retention-days: 7
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ build/
*.spvchain
*.wallet

.DS_Store
.DS_Store
local.properties
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
buildscript {
ext.version = '2.0.1'
ext.kotlin_version = '1.8.22'
ext.version = '2.0.2-SNAPSHOT'
ext.kotlin_version = '2.1.20'
ext.dashj_version = '21.1.7'
repositories {
google() // Required for Android library and application projects
Expand All @@ -10,7 +10,7 @@ buildscript {

dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.android.tools.build:gradle:8.1.4' // Use the latest version
classpath 'com.android.tools.build:gradle:8.5.1'
classpath "com.google.protobuf:protobuf-gradle-plugin:0.9.4"
classpath 'org.jreleaser:jreleaser-gradle-plugin:1.17.0'
}
Expand Down
8 changes: 4 additions & 4 deletions dash-sdk-android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ android {

defaultConfig {
minSdk 24
targetSdk 32
targetSdk 35
versionCode 1
versionName project.rootProject.ext.version

Expand All @@ -26,15 +26,15 @@ android {
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}

packagingOptions {
pickFirst '**/*.so'
}

ndkVersion = "23.1.7779620"
ndkVersion = "29.0.14206865"
externalNativeBuild {
cmake {
path 'src/main/cpp/CMakeLists.txt'
Expand Down
2 changes: 1 addition & 1 deletion dash-sdk-android/src/main/rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "dash-sdk-bindings"
version = "2.0.0"
version = "2.0.2"
edition = "2021"

[dependencies]
Expand Down
2 changes: 1 addition & 1 deletion dash-sdk-bindings/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "dash-sdk-bindings"
version = "2.0.0"
version = "2.0.2"
edition = "2021"

[dependencies]
Expand Down
1 change: 1 addition & 0 deletions dash-sdk-java/src/main/cpp/java_map_string_value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Created by Eric Britten on 3/24/24.
//
#include <jni.h>
#include <string.h>
#include "conversions.h"

// TODO: This function needs to handle all of the variants
Expand Down
2 changes: 1 addition & 1 deletion dash-sdk-java/src/main/swig/identity.i
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
}

struct dpp_identity_identity_public_key_v0_IdentityPublicKeyV0 * getPublicKeyById(uint32_t id) {
for (int i = 0; i < $self->public_keys->count; ++i) {
for (uintptr_t i = 0; i < $self->public_keys->count; ++i) {
if ($self->public_keys->keys[i]->_0 == id)
return $self->public_keys->values[i]->v0._0;
}
Expand Down
14 changes: 7 additions & 7 deletions dash-sdk-java/src/main/swig/myexception.i
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
%exception {
try {
$action
} catch(std::string x) {
} catch(std::string& x) {
SWIG_exception(SWIG_JavaUnknownError, x.c_str());
} catch(std::runtime_error x) {
SWIG_exception(SWIG_RuntimeError, x.what());
} catch(std::invalid_argument x) {
} catch(std::runtime_error& x) {
SWIG_exception(SWIG_RuntimeError, x.what());
} catch(std::invalid_argument& x) {
SWIG_exception(SWIG_TypeError, x.what());
} catch(std::exception x) {
SWIG_exception(SWIG_UnknownError, x.what());
} catch(...) {
} catch(std::exception& x) {
SWIG_exception(SWIG_UnknownError, x.what());
} catch(...) {
SWIG_exception(SWIG_UnknownError,"Unknown exception");
}
}
10 changes: 5 additions & 5 deletions dashj-platform-android-simple/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ plugins {

android {
namespace "org.dashj.platform"
compileSdk 32
compileSdk 34

defaultConfig {
minSdk 24
targetSdk 32
targetSdk 35

testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
Expand All @@ -23,15 +23,15 @@ android {
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}

packagingOptions {
pickFirst '**/*.so'
}

ndkVersion "25.2.9519653"
ndkVersion "29.0.14206865"
}

task buildRustRelease() {
Expand Down
2 changes: 1 addition & 1 deletion dpp/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ plugins {
id 'java'
id 'org.jetbrains.kotlin.jvm'
id 'com.google.protobuf'
id('io.gitlab.arturbosch.detekt').version("1.19.0")
id('io.gitlab.arturbosch.detekt').version("1.23.7")
id 'maven-publish'
id 'signing'
id 'org.jreleaser'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1668,7 +1668,7 @@ class BlockchainIdentity {
) {
val query = DocumentQuery.Builder()
.where("normalizedParentDomainName", "==", Names.DEFAULT_PARENT_DOMAIN)
.where(listOf("normalizedLabel", "in", usernames.map { it.toLowerCase() }))
.where(listOf("normalizedLabel", "in", usernames.map { it.lowercase() }))
.orderBy("normalizedParentDomainName")
.orderBy("normalizedLabel")
.build()
Expand All @@ -1677,7 +1677,7 @@ class BlockchainIdentity {
if (nameDocuments.isNotEmpty()) {
val usernamesLeft = ArrayList(usernames)
for (username in usernames) {
val normalizedName = username.toLowerCase()
val normalizedName = username.lowercase()
for (nameDocument in nameDocuments) {
if (nameDocument.data["normalizedLabel"] == normalizedName) {
val usernameStatus = usernameStatuses[username]!!
Expand Down Expand Up @@ -1733,13 +1733,13 @@ class BlockchainIdentity {
): Pair<Boolean, List<String>> {
val query = DocumentQuery.Builder()
.where("normalizedParentDomainName", "==", Names.DEFAULT_PARENT_DOMAIN)
.where(listOf("normalizedLabel", "in", usernames.map { "${it.toLowerCase()}" })).build()
.where(listOf("normalizedLabel", "in", usernames.map { "${it.lowercase()}" })).build()
val nameDocuments = platform.documents.get(Names.DPNS_DOMAIN_DOCUMENT, query)

if (nameDocuments.isNotEmpty()) {
val usernamesLeft = ArrayList(usernames)
for (username in usernames) {
val normalizedName = username.toLowerCase()
val normalizedName = username.lowercase()
for (nameDocument in nameDocuments) {
if (nameDocument.data["normalizedLabel"] == normalizedName) {
val usernameStatus = usernameStatuses[username]!!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ abstract class DocumentTransition(rawStateTransition: MutableMap<String, Any?>,
}

fun getByName(name: String): Action {
return values.filter { it.name.toLowerCase() == name }[0]
return values.filter { it.name.lowercase() == name }[0]
}

fun getValidNames(): List<String> {
return values.map { it.name.toLowerCase() }
return values.map { it.name.lowercase() }
}
}
}
Expand Down
9 changes: 0 additions & 9 deletions local.properties

This file was deleted.

2 changes: 1 addition & 1 deletion platform-mobile/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "platform-mobile"
version = "2.0.0"
version = "2.0.2"
edition = "2021"

[dependencies]
Expand Down
Loading