diff --git a/Cargo.lock b/Cargo.lock index c146338f3d6..f79d228f4a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1407,7 +1407,6 @@ dependencies = [ [[package]] name = "dash-network" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=2bd764fdc071828939d9dc8dd872c39bae906b04#2bd764fdc071828939d9dc8dd872c39bae906b04" dependencies = [ "bincode", "bincode_derive", @@ -1484,7 +1483,6 @@ dependencies = [ [[package]] name = "dash-spv" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=2bd764fdc071828939d9dc8dd872c39bae906b04#2bd764fdc071828939d9dc8dd872c39bae906b04" dependencies = [ "anyhow", "async-trait", @@ -1517,14 +1515,12 @@ dependencies = [ [[package]] name = "dash-spv-ffi" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=2bd764fdc071828939d9dc8dd872c39bae906b04#2bd764fdc071828939d9dc8dd872c39bae906b04" dependencies = [ "cbindgen 0.29.2", "clap", "dash-spv", "dashcore", "env_logger 0.10.2", - "futures", "hex", "key-wallet", "key-wallet-ffi", @@ -1543,7 +1539,6 @@ dependencies = [ [[package]] name = "dashcore" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=2bd764fdc071828939d9dc8dd872c39bae906b04#2bd764fdc071828939d9dc8dd872c39bae906b04" dependencies = [ "anyhow", "base64-compat", @@ -1569,12 +1564,10 @@ dependencies = [ [[package]] name = "dashcore-private" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=2bd764fdc071828939d9dc8dd872c39bae906b04#2bd764fdc071828939d9dc8dd872c39bae906b04" [[package]] name = "dashcore-rpc" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=2bd764fdc071828939d9dc8dd872c39bae906b04#2bd764fdc071828939d9dc8dd872c39bae906b04" dependencies = [ "dashcore-rpc-json", "hex", @@ -1587,7 +1580,6 @@ dependencies = [ [[package]] name = "dashcore-rpc-json" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=2bd764fdc071828939d9dc8dd872c39bae906b04#2bd764fdc071828939d9dc8dd872c39bae906b04" dependencies = [ "bincode", "dashcore", @@ -1602,7 +1594,6 @@ dependencies = [ [[package]] name = "dashcore_hashes" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=2bd764fdc071828939d9dc8dd872c39bae906b04#2bd764fdc071828939d9dc8dd872c39bae906b04" dependencies = [ "bincode", "dashcore-private", @@ -3422,7 +3413,6 @@ dependencies = [ [[package]] name = "key-wallet" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=2bd764fdc071828939d9dc8dd872c39bae906b04#2bd764fdc071828939d9dc8dd872c39bae906b04" dependencies = [ "aes", "async-trait", @@ -3452,7 +3442,6 @@ dependencies = [ [[package]] name = "key-wallet-ffi" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=2bd764fdc071828939d9dc8dd872c39bae906b04#2bd764fdc071828939d9dc8dd872c39bae906b04" dependencies = [ "cbindgen 0.29.2", "dash-network", @@ -3468,7 +3457,6 @@ dependencies = [ [[package]] name = "key-wallet-manager" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=2bd764fdc071828939d9dc8dd872c39bae906b04#2bd764fdc071828939d9dc8dd872c39bae906b04" dependencies = [ "async-trait", "bincode", diff --git a/packages/rs-dapi/Cargo.toml b/packages/rs-dapi/Cargo.toml index f37bfb906c0..e16cd1cc0e0 100644 --- a/packages/rs-dapi/Cargo.toml +++ b/packages/rs-dapi/Cargo.toml @@ -87,8 +87,8 @@ prometheus = "0.14" once_cell = "1.19" # Dash Core RPC client -dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04" } -dash-spv = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04" } +dashcore-rpc = { path = "../../../rust-dashcore/rpc-client" } +dash-spv = { path = "../../../rust-dashcore/dash-spv" } rs-dash-event-bus = { path = "../rs-dash-event-bus" } diff --git a/packages/rs-dpp/Cargo.toml b/packages/rs-dpp/Cargo.toml index c610998a5fe..0925243621b 100644 --- a/packages/rs-dpp/Cargo.toml +++ b/packages/rs-dpp/Cargo.toml @@ -24,7 +24,7 @@ chrono = { version = "0.4.35", default-features = false, features = [ ] } chrono-tz = { version = "0.8", optional = true } ciborium = { version = "0.2.2", optional = true } -dashcore = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04", features = [ +dashcore = { path = "../../../rust-dashcore/dash", features = [ "std", "secp-recovery", "rand", @@ -32,10 +32,10 @@ dashcore = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc0 "serde", "eddsa", ], default-features = false } -key-wallet = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04", optional = true } -key-wallet-manager = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04", optional = true } -dash-spv = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04", optional = true } -dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04", optional = true } +key-wallet = { path = "../../../rust-dashcore/key-wallet", optional = true } +key-wallet-manager = { path = "../../../rust-dashcore/key-wallet-manager", optional = true } +dash-spv = { path = "../../../rust-dashcore/dash-spv", optional = true } +dashcore-rpc = { path = "../../../rust-dashcore/rpc-client", optional = true } env_logger = { version = "0.11" } getrandom = { version = "0.2", features = ["js"] } diff --git a/packages/rs-platform-encryption/Cargo.toml b/packages/rs-platform-encryption/Cargo.toml index 1897aaba94e..bb014a2d82c 100644 --- a/packages/rs-platform-encryption/Cargo.toml +++ b/packages/rs-platform-encryption/Cargo.toml @@ -8,7 +8,7 @@ description = "Cryptographic utilities for Dash Platform (DIP-15 DashPay encrypt [dependencies] # Cryptography -dashcore = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04" } +dashcore = { path = "../../../rust-dashcore/dash" } aes = "0.8" cbc = "0.1" sha2 = "0.10" diff --git a/packages/rs-platform-wallet-ffi/Cargo.toml b/packages/rs-platform-wallet-ffi/Cargo.toml index 88528457280..20b3e9c3406 100644 --- a/packages/rs-platform-wallet-ffi/Cargo.toml +++ b/packages/rs-platform-wallet-ffi/Cargo.toml @@ -23,8 +23,8 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" # Core dependencies (for Network type) -dashcore = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04" } -key-wallet = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04" } +dashcore = { path = "../../../rust-dashcore/dash" } +key-wallet = { path = "../../../rust-dashcore/key-wallet" } # Error handling thiserror = "1.0" diff --git a/packages/rs-platform-wallet/Cargo.toml b/packages/rs-platform-wallet/Cargo.toml index 01adaeacfbb..24c3769e577 100644 --- a/packages/rs-platform-wallet/Cargo.toml +++ b/packages/rs-platform-wallet/Cargo.toml @@ -13,11 +13,11 @@ dash-sdk = { path = "../rs-sdk", default-features = false, features = ["dashpay- platform-encryption = { path = "../rs-platform-encryption" } # Key wallet dependencies (from rust-dashcore) -key-wallet = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04" } -key-wallet-manager = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04", optional = true } +key-wallet = { path = "../../../rust-dashcore/key-wallet" } +key-wallet-manager = { path = "../../../rust-dashcore/key-wallet-manager", optional = true } # Core dependencies -dashcore = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04" } +dashcore = { path = "../../../rust-dashcore/dash" } # Standard dependencies thiserror = "1.0" diff --git a/packages/rs-sdk-ffi/Cargo.toml b/packages/rs-sdk-ffi/Cargo.toml index f55e3e6eac2..46e90a14dd8 100644 --- a/packages/rs-sdk-ffi/Cargo.toml +++ b/packages/rs-sdk-ffi/Cargo.toml @@ -23,7 +23,7 @@ simple-signer = { path = "../simple-signer" } # Core SDK integration (always included for unified SDK) -dash-spv-ffi = { git = "https://github.com/dashpay/rust-dashcore", rev = "2bd764fdc071828939d9dc8dd872c39bae906b04", optional = true } +dash-spv-ffi = { path = "../../../rust-dashcore/dash-spv-ffi", optional = true } # Platform Wallet integration for DashPay support platform-wallet-ffi = { path = "../rs-platform-wallet-ffi" } diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Wallet.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Wallet.swift index 1ed4ae7e7de..ca3fdf9a7fe 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Wallet.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Wallet.swift @@ -516,6 +516,13 @@ public class Wallet { self.ownsHandle = false } + /// Owning initializer for wallets returned by FFI functions that allocate a new Box. + /// The caller transfers ownership — deinit will call wallet_free(). + internal init(owningHandle handle: UnsafeRawPointer) { + self.handle = UnsafeMutablePointer(mutating: handle.bindMemory(to: FFIWallet.self, capacity: 1)) + self.ownsHandle = true + } + deinit { if ownsHandle { diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift index e93c00b9286..b1e7d16ce80 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift @@ -165,8 +165,9 @@ public class WalletManager { } throw KeyWalletError(ffiError: error) } - // Wrap as non-owning wallet; the manager retains ownership - let wallet = Wallet(nonOwningHandle: UnsafeRawPointer(ptr)) + // The FFI function allocates a new Box via Box::into_raw — + // we own it and must free it via wallet_free() when done. + let wallet = Wallet(owningHandle: UnsafeRawPointer(ptr)) return wallet } @@ -397,48 +398,61 @@ public class WalletManager { guard !outputs.isEmpty else { throw KeyWalletError.invalidInput("Transaction must have at least one output") } - - var error = FFIError() - var txBytesPtr: UnsafeMutablePointer? - var txLen: size_t = 0 - - var fee: UInt64 = 0; - let wallet = try self.getWallet(id: wallet.walletId)! - - let ffiOutputs = outputs.map { $0.toFFI() } - - let success = ffiOutputs.withUnsafeBufferPointer { outputsPtr in - wallet_build_and_sign_transaction( - self.handle, - wallet.ffiHandle, - accIndex, - outputsPtr.baseAddress, - outputs.count, - feeRate.intoFFI(), - &fee, - &txBytesPtr, - &txLen, - &error) - } - - defer { - if error.message != nil {8 - error_message_free(error.message) + let ffiWallet = try self.getWallet(id: wallet.walletId)! + + // withExtendedLifetime keeps ffiWallet alive for the entire duration of + // the closure. Without this, Swift's ARC optimizer may release the + // Wallet object (and call wallet_free) after extracting the raw + // ffiHandle pointer but BEFORE the Rust FFI call finishes — causing a + // use-after-free / EXC_BAD_ACCESS in the Rust code. + return try withExtendedLifetime(ffiWallet) { + var error = FFIError() + var txBytesPtr: UnsafeMutablePointer? + var txLen: size_t = 0 + var fee: UInt64 = 0 + + let ffiOutputs = outputs.map { $0.toFFI() } + + // Free strdup'd C strings after the FFI call completes + defer { + for output in ffiOutputs { + free(UnsafeMutablePointer(mutating: output.address)) + } } - if let ptr = txBytesPtr { - transaction_bytes_free(ptr) + + let success = ffiOutputs.withUnsafeBufferPointer { outputsPtr in + wallet_build_and_sign_transaction( + self.handle, + ffiWallet.ffiHandle, + accIndex, + outputsPtr.baseAddress, + outputs.count, + feeRate.intoFFI(), + &fee, + &txBytesPtr, + &txLen, + &error) } + + defer { + if error.message != nil { + error_message_free(error.message) + } + if let ptr = txBytesPtr { + transaction_bytes_free(ptr) + } + } + + guard success, let ptr = txBytesPtr else { + throw KeyWalletError(ffiError: error) + } + + // Copy the transaction data before freeing + let txData = Data(bytes: ptr, count: txLen) + + return (txData, fee) } - - guard success, let ptr = txBytesPtr else { - throw KeyWalletError(ffiError: error) - } - - // Copy the transaction data before freeing - let txData = Data(bytes: ptr, count: txLen) - - return (txData, fee) } // MARK: - Block Height Management diff --git a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/SendTransactionView.swift b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/SendTransactionView.swift index 896dece1b04..96f2229130c 100644 --- a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/SendTransactionView.swift +++ b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/SendTransactionView.swift @@ -128,6 +128,7 @@ struct SendTransactionView: View { self.fee = fee self.tx = tx } catch { + self.error = error self.fee = 0 self.tx = nil } @@ -169,4 +170,4 @@ struct SendTransactionView: View { let decimalPart = dash % 100_000_000 return String(format: "~%llu.%08llu DASH", dashPart, decimalPart) } -} \ No newline at end of file +}