Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
49 changes: 32 additions & 17 deletions packages/rs-sdk-ffi/build_ios.sh
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ fi
# Build dash-spv-ffi from local rust-dashcore for device and simulator
RUST_DASHCORE_PATH="$PROJECT_ROOT/../rust-dashcore"
SPV_CRATE_PATH="$RUST_DASHCORE_PATH/dash-spv-ffi"
SPV_TARGET_DIR="$RUST_DASHCORE_PATH/target"
if [ -d "$SPV_CRATE_PATH" ]; then
echo -e "${GREEN}Building dash-spv-ffi (local rust-dashcore)${NC}"
pushd "$SPV_CRATE_PATH" >/dev/null
Expand All @@ -343,6 +344,13 @@ if [ -d "$SPV_CRATE_PATH" ]; then
cargo build --lib --target aarch64-apple-ios-sim --release > /tmp/cargo_build_spv_sim_arm.log 2>&1 || { echo -e "${RED}✗ dash-spv-ffi sim (arm64) build failed${NC}"; cat /tmp/cargo_build_spv_sim_arm.log; exit 1; }
cargo build --lib --target x86_64-apple-ios --release > /tmp/cargo_build_spv_sim_x86.log 2>&1 || { echo -e "${RED}✗ dash-spv-ffi sim (x86_64) build failed${NC}"; cat /tmp/cargo_build_spv_sim_x86.log; exit 1; }
fi
elif [ "$BUILD_ARCH" = "x86" ]; then
if [ -n "${RUST_DASHCORE_TOOLCHAIN:-}" ]; then
echo -e "${GREEN}Using toolchain '+${RUST_DASHCORE_TOOLCHAIN}' for sim build${NC}"
cargo +"${RUST_DASHCORE_TOOLCHAIN}" build --lib --target x86_64-apple-ios --release > /tmp/cargo_build_spv_sim_x86.log 2>&1 || { echo -e "${RED}✗ dash-spv-ffi sim (x86_64) build failed${NC}"; cat /tmp/cargo_build_spv_sim_x86.log; exit 1; }
else
cargo build --lib --target x86_64-apple-ios --release > /tmp/cargo_build_spv_sim_x86.log 2>&1 || { echo -e "${RED}✗ dash-spv-ffi sim (x86_64) build failed${NC}"; cat /tmp/cargo_build_spv_sim_x86.log; exit 1; }
fi
else
if [ -n "${RUST_DASHCORE_TOOLCHAIN:-}" ]; then
echo -e "${GREEN}Using toolchain '+${RUST_DASHCORE_TOOLCHAIN}' for sim build${NC}"
Expand Down Expand Up @@ -377,12 +385,12 @@ if [ "$BUILD_ARCH" != "x86" ]; then
mkdir -p "$OUTPUT_DIR/device"
cp "$PROJECT_ROOT/target/aarch64-apple-ios/release/librs_sdk_ffi.a" "$OUTPUT_DIR/device/"
# Merge with dash-spv-ffi device lib if available
if [ -f "$SPV_CRATE_PATH/target/aarch64-apple-ios/release/libdash_spv_ffi.a" ]; then
if [ -f "$SPV_TARGET_DIR/aarch64-apple-ios/release/libdash_spv_ffi.a" ]; then
echo -e "${GREEN}Merging device libs (rs-sdk-ffi + dash-spv-ffi)${NC}"
libtool -static -o "$OUTPUT_DIR/device/libDashSDKFFI_combined.a" \
libtool -static -o "$OUTPUT_DIR/device/librs_sdk_ffi.tmp.a" \
"$OUTPUT_DIR/device/librs_sdk_ffi.a" \
"$SPV_CRATE_PATH/target/aarch64-apple-ios/release/libdash_spv_ffi.a"
COMBINED_DEVICE_LIB=1
"$SPV_TARGET_DIR/aarch64-apple-ios/release/libdash_spv_ffi.a"
mv "$OUTPUT_DIR/device/librs_sdk_ffi.tmp.a" "$OUTPUT_DIR/device/librs_sdk_ffi.a"
fi
fi

Expand Down Expand Up @@ -435,30 +443,37 @@ rm -rf "$OUTPUT_DIR/$FRAMEWORK_NAME.xcframework"
XCFRAMEWORK_CMD="xcodebuild -create-xcframework"

if [ "$BUILD_ARCH" != "x86" ] && [ -f "$OUTPUT_DIR/device/librs_sdk_ffi.a" ]; then
if [ -n "${COMBINED_DEVICE_LIB:-}" ] && [ -f "$OUTPUT_DIR/device/libDashSDKFFI_combined.a" ]; then
XCFRAMEWORK_CMD="$XCFRAMEWORK_CMD -library $OUTPUT_DIR/device/libDashSDKFFI_combined.a -headers $HEADERS_DIR"
else
XCFRAMEWORK_CMD="$XCFRAMEWORK_CMD -library $OUTPUT_DIR/device/librs_sdk_ffi.a -headers $HEADERS_DIR"
fi
XCFRAMEWORK_CMD="$XCFRAMEWORK_CMD -library $OUTPUT_DIR/device/librs_sdk_ffi.a -headers $HEADERS_DIR"
fi

if [ -f "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" ]; then
# Try to merge with SPV sim lib if it exists
SIM_SPV_LIB=""
if [ -f "$SPV_CRATE_PATH/target/aarch64-apple-ios-sim/release/libdash_spv_ffi.a" ]; then
SIM_SPV_LIB="$SPV_CRATE_PATH/target/aarch64-apple-ios-sim/release/libdash_spv_ffi.a"
elif [ -f "$SPV_CRATE_PATH/target/x86_64-apple-ios/release/libdash_spv_ffi.a" ]; then
SIM_SPV_LIB="$SPV_CRATE_PATH/target/x86_64-apple-ios/release/libdash_spv_ffi.a"
if [ "$BUILD_ARCH" = "universal" ]; then
ARM_SIM_SPV_LIB="$SPV_TARGET_DIR/aarch64-apple-ios-sim/release/libdash_spv_ffi.a"
X86_SIM_SPV_LIB="$SPV_TARGET_DIR/x86_64-apple-ios/release/libdash_spv_ffi.a"
if [ -f "$ARM_SIM_SPV_LIB" ] && [ -f "$X86_SIM_SPV_LIB" ]; then
lipo -create \
"$ARM_SIM_SPV_LIB" \
"$X86_SIM_SPV_LIB" \
-output "$OUTPUT_DIR/simulator/libdash_spv_ffi.a"
SIM_SPV_LIB="$OUTPUT_DIR/simulator/libdash_spv_ffi.a"
elif [ -f "$ARM_SIM_SPV_LIB" ] || [ -f "$X86_SIM_SPV_LIB" ]; then
echo -e "${YELLOW}⚠ Universal build: missing one SPV sim lib (arm64: $([ -f \"$ARM_SIM_SPV_LIB\" ] && echo found || echo missing), x86_64: $([ -f \"$X86_SIM_SPV_LIB\" ] && echo found || echo missing))${NC}" >&2
fi
elif [ "$BUILD_ARCH" = "x86" ] && [ -f "$SPV_TARGET_DIR/x86_64-apple-ios/release/libdash_spv_ffi.a" ]; then
SIM_SPV_LIB="$SPV_TARGET_DIR/x86_64-apple-ios/release/libdash_spv_ffi.a"
elif [ -f "$SPV_TARGET_DIR/aarch64-apple-ios-sim/release/libdash_spv_ffi.a" ]; then
SIM_SPV_LIB="$SPV_TARGET_DIR/aarch64-apple-ios-sim/release/libdash_spv_ffi.a"
fi
if [ -n "$SIM_SPV_LIB" ]; then
echo -e "${GREEN}Merging simulator libs (rs-sdk-ffi + dash-spv-ffi)${NC}"
libtool -static -o "$OUTPUT_DIR/simulator/libDashSDKFFI_combined.a" \
libtool -static -o "$OUTPUT_DIR/simulator/librs_sdk_ffi.tmp.a" \
"$OUTPUT_DIR/simulator/librs_sdk_ffi.a" \
"$SIM_SPV_LIB"
XCFRAMEWORK_CMD="$XCFRAMEWORK_CMD -library $OUTPUT_DIR/simulator/libDashSDKFFI_combined.a -headers $HEADERS_DIR"
else
XCFRAMEWORK_CMD="$XCFRAMEWORK_CMD -library $OUTPUT_DIR/simulator/librs_sdk_ffi.a -headers $HEADERS_DIR"
mv "$OUTPUT_DIR/simulator/librs_sdk_ffi.tmp.a" "$OUTPUT_DIR/simulator/librs_sdk_ffi.a"
fi
XCFRAMEWORK_CMD="$XCFRAMEWORK_CMD -library $OUTPUT_DIR/simulator/librs_sdk_ffi.a -headers $HEADERS_DIR"
fi

XCFRAMEWORK_CMD="$XCFRAMEWORK_CMD -output $OUTPUT_DIR/$FRAMEWORK_NAME.xcframework"
Expand Down
12 changes: 9 additions & 3 deletions packages/rs-sdk-ffi/src/address_sync/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@ pub type GetGapLimitFn = unsafe extern "C" fn(context: *mut c_void) -> u32;

/// Function pointer type for checking if there are pending addresses
pub type HasPendingFn = unsafe extern "C" fn(context: *mut c_void) -> bool;
/// Nullable function pointer for checking if there are pending addresses
pub type NullableHasPendingFn = Option<unsafe extern "C" fn(context: *mut c_void) -> bool>;

/// Function pointer type for getting the highest found index
///
/// Returns the highest found index, or u32::MAX if none found
pub type GetHighestFoundIndexFn = unsafe extern "C" fn(context: *mut c_void) -> u32;
/// Nullable function pointer for getting the highest found index
pub type NullableGetHighestFoundIndexFn = Option<unsafe extern "C" fn(context: *mut c_void) -> u32>;

/// Function pointer type for handling a found address
///
Expand All @@ -43,6 +47,8 @@ pub type OnAddressAbsentFn =

/// Optional destructor for cleanup
pub type DestroyProviderFn = unsafe extern "C" fn(context: *mut c_void);
/// Nullable function pointer for provider cleanup
pub type NullableDestroyProviderFn = Option<unsafe extern "C" fn(context: *mut c_void)>;

/// VTable for address provider callbacks
#[repr(C)]
Expand All @@ -61,14 +67,14 @@ pub struct AddressProviderVTable {

/// Check if there are still pending addresses
/// If null, the default implementation (pending_addresses is non-empty) is used
pub has_pending: Option<HasPendingFn>,
pub has_pending: NullableHasPendingFn,

/// Get the highest found index
/// If null, returns None
pub highest_found_index: Option<GetHighestFoundIndexFn>,
pub highest_found_index: NullableGetHighestFoundIndexFn,

/// Optional destructor for cleanup
pub destroy: Option<DestroyProviderFn>,
pub destroy: NullableDestroyProviderFn,
}
Comment on lines 76 to 78
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Search for Drop implementations for AddressProviderFFI and CallbackAddressProvider
rg -n "impl Drop for AddressProviderFFI|impl Drop for CallbackAddressProvider" --type rust -C 3

Repository: dashpay/platform

Length of output: 42


🏁 Script executed:

# Check the file under review to understand the structure
cat -n packages/rs-sdk-ffi/src/address_sync/provider.rs

Repository: dashpay/platform

Length of output: 10790


🏁 Script executed:

# Search more broadly for Drop implementations in the FFI codebase
rg -n "impl Drop" packages/rs-sdk-ffi/ --type rust

Repository: dashpay/platform

Length of output: 42


Implement Drop for AddressProviderFFI to ensure the destroy callback is invoked during cleanup.

Currently, AddressProviderFFI has no Drop implementation, so the optional destroy callback is never called. This leaves resource cleanup to the FFI consumer, which is error-prone. Add a Drop impl that safely calls destroy if provided:

impl Drop for AddressProviderFFI {
    fn drop(&mut self) {
        unsafe {
            let vtable = &*self.vtable;
            if let Some(destroy) = vtable.destroy {
                destroy(self.context);
            }
        }
    }
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/rs-sdk-ffi/src/address_sync/provider.rs` around lines 76 - 78,
AddressProviderFFI never invokes its optional destroy callback on drop, leaving
FFI-side resources uncleaned; add a Drop impl for AddressProviderFFI that, in
drop, unsafely dereferences self.vtable, checks vtable.destroy (the
NullableDestroyProviderFn) for Some, and if present calls it with self.context
so the FFI-provided destructor runs during Rust cleanup.


/// FFI-compatible address provider using callbacks
Expand Down
16 changes: 12 additions & 4 deletions packages/swift-sdk/build_ios.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,26 @@ else
fi

CHECK_OK=1
if nm -gU "$LIB_SIM_MAIN" 2>/dev/null | "${SEARCH_CMD[@]}" "_dash_spv_ffi_config_add_peer" >/dev/null; then
NM_MAIN_OUTPUT="$(mktemp)"
NM_SPV_OUTPUT="$(mktemp)"
trap 'rm -f "$NM_MAIN_OUTPUT" "$NM_SPV_OUTPUT"' EXIT
nm -gU "$LIB_SIM_MAIN" >"$NM_MAIN_OUTPUT" 2>/dev/null || true
if [[ -f "$LIB_SIM_SPV" ]]; then
nm -gU "$LIB_SIM_SPV" >"$NM_SPV_OUTPUT" 2>/dev/null || true
fi

if "${SEARCH_CMD[@]}" "_dash_spv_ffi_config_add_peer" "$NM_MAIN_OUTPUT" >/dev/null; then
:
elif [[ -f "$LIB_SIM_SPV" ]] && nm -gU "$LIB_SIM_SPV" 2>/dev/null | "${SEARCH_CMD[@]}" "_dash_spv_ffi_config_add_peer" >/dev/null; then
elif [[ -f "$LIB_SIM_SPV" ]] && "${SEARCH_CMD[@]}" "_dash_spv_ffi_config_add_peer" "$NM_SPV_OUTPUT" >/dev/null; then
:
else
echo "❌ Missing symbol: dash_spv_ffi_config_add_peer (in both main and spv libs)"
CHECK_OK=0
fi

if nm -gU "$LIB_SIM_MAIN" 2>/dev/null | "${SEARCH_CMD[@]}" "_dash_spv_ffi_config_set_restrict_to_configured_peers" >/dev/null; then
if "${SEARCH_CMD[@]}" "_dash_spv_ffi_config_set_restrict_to_configured_peers" "$NM_MAIN_OUTPUT" >/dev/null; then
:
elif [[ -f "$LIB_SIM_SPV" ]] && nm -gU "$LIB_SIM_SPV" 2>/dev/null | "${SEARCH_CMD[@]}" "_dash_spv_ffi_config_set_restrict_to_configured_peers" >/dev/null; then
elif [[ -f "$LIB_SIM_SPV" ]] && "${SEARCH_CMD[@]}" "_dash_spv_ffi_config_set_restrict_to_configured_peers" "$NM_SPV_OUTPUT" >/dev/null; then
:
else
echo "❌ Missing symbol: dash_spv_ffi_config_set_restrict_to_configured_peers (in both main and spv libs)"
Expand Down
Loading