Skip to content

Commit

Permalink
Merge pull request #669 from Syn-McJ/feat/coinjoin-wifi-warning
Browse files Browse the repository at this point in the history
feat(coinjoin): wifi warning
  • Loading branch information
Syn-McJ authored Oct 15, 2024
2 parents 58996a0 + 8e02651 commit 15fde64
Show file tree
Hide file tree
Showing 55 changed files with 621 additions and 247 deletions.
24 changes: 12 additions & 12 deletions DashWallet.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -10290,7 +10290,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 8.2.0;
MARKETING_VERSION = 8.3.0;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand Down Expand Up @@ -10430,7 +10430,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 8.2.0;
MARKETING_VERSION = 8.3.0;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand Down Expand Up @@ -10604,7 +10604,7 @@
EXCLUDED_ARCHS = "";
IBSC_MODULE = WatchApp_Extension;
INFOPLIST_FILE = WatchApp/Info.plist;
MARKETING_VERSION = 8.2.0;
MARKETING_VERSION = 8.3.0;
PRODUCT_BUNDLE_IDENTIFIER = org.dashfoundation.dash.watchkitapp;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = watchos;
Expand All @@ -10626,7 +10626,7 @@
EXCLUDED_ARCHS = "";
IBSC_MODULE = WatchApp_Extension;
INFOPLIST_FILE = WatchApp/Info.plist;
MARKETING_VERSION = 8.2.0;
MARKETING_VERSION = 8.3.0;
PRODUCT_BUNDLE_IDENTIFIER = org.dashfoundation.dash.watchkitapp;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = watchos;
Expand All @@ -10651,7 +10651,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 8.2.0;
MARKETING_VERSION = 8.3.0;
PRODUCT_BUNDLE_IDENTIFIER = org.dashfoundation.dash.watchkitapp.watchkitextension;
PRODUCT_NAME = "${TARGET_NAME}";
SDKROOT = watchos;
Expand All @@ -10678,7 +10678,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 8.2.0;
MARKETING_VERSION = 8.3.0;
PRODUCT_BUNDLE_IDENTIFIER = org.dashfoundation.dash.watchkitapp.watchkitextension;
PRODUCT_NAME = "${TARGET_NAME}";
SDKROOT = watchos;
Expand Down Expand Up @@ -11418,7 +11418,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 8.2.0;
MARKETING_VERSION = 8.3.0;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand Down Expand Up @@ -11587,7 +11587,7 @@
EXCLUDED_ARCHS = "";
IBSC_MODULE = WatchApp_Extension;
INFOPLIST_FILE = WatchApp/Info.plist;
MARKETING_VERSION = 8.2.0;
MARKETING_VERSION = 8.3.0;
PRODUCT_BUNDLE_IDENTIFIER = org.dashfoundation.dash.watchkitapp;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = watchos;
Expand All @@ -11612,7 +11612,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 8.2.0;
MARKETING_VERSION = 8.3.0;
PRODUCT_BUNDLE_IDENTIFIER = org.dashfoundation.dash.watchkitapp.watchkitextension;
PRODUCT_NAME = "${TARGET_NAME}";
SDKROOT = watchos;
Expand Down Expand Up @@ -11729,7 +11729,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 8.2.0;
MARKETING_VERSION = 8.3.0;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand Down Expand Up @@ -11896,7 +11896,7 @@
EXCLUDED_ARCHS = "";
IBSC_MODULE = WatchApp_Extension;
INFOPLIST_FILE = WatchApp/Info.plist;
MARKETING_VERSION = 8.2.0;
MARKETING_VERSION = 8.3.0;
PRODUCT_BUNDLE_IDENTIFIER = org.dashfoundation.dash.watchkitapp;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = watchos;
Expand All @@ -11921,7 +11921,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 8.2.0;
MARKETING_VERSION = 8.3.0;
PRODUCT_BUNDLE_IDENTIFIER = org.dashfoundation.dash.watchkitapp.watchkitextension;
PRODUCT_NAME = "${TARGET_NAME}";
SDKROOT = watchos;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,9 @@ extension SyncingActivityMonitor {
state = .noConnection
return
}
updateProgress()
DispatchQueue.main.async {
self.updateProgress()
}
}

private func updateProgress() {
Expand Down
105 changes: 48 additions & 57 deletions DashWallet/Sources/Models/CoinJoin/CoinJoinService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ public class CoinJoinServiceWrapper: NSObject {
}
}

class CoinJoinService: NSObject {
class CoinJoinService: NSObject, NetworkReachabilityHandling {
var networkStatusDidChange: ((NetworkStatus) -> ())?
var reachabilityObserver: Any!

static let shared: CoinJoinService = {
return CoinJoinService()
}()
Expand All @@ -85,7 +88,6 @@ class CoinJoinService: NSObject {
private let updateMixingStateMutex = NSLock()
private var coinJoinManager: DSCoinJoinManager? = nil
private var hasAnonymizableBalance: Bool = false
private var networkStatus: NetworkStatus = .online
private var timeSkew: TimeInterval = 0
private var workingChain: ChainType

Expand All @@ -95,42 +97,50 @@ class CoinJoinService: NSObject {
}
}

private var savedMode: Int {
private var currentMode: CoinJoinMode {
get {
return UserDefaults.standard.integer(forKey: chainModeKey)
let current = CoinJoinMode(rawValue: UserDefaults.standard.integer(forKey: chainModeKey)) ?? .none

if self.mode != current {
self.mode = current
}

return current
}
set(value) { UserDefaults.standard.set(value, forKey: chainModeKey) }
}

@Published private(set) var mode: CoinJoinMode = .none {
didSet {
savedMode = mode.rawValue
set(value) {
self.mode = value
UserDefaults.standard.set(value.rawValue, forKey: chainModeKey)
}
}

@Published private(set) var mode: CoinJoinMode = .none
@Published var mixingState: MixingStatus = .notStarted
@Published private(set) var progress = CoinJoinProgress(progress: 0.0, totalBalance: 0, coinJoinBalance: 0)
@Published private(set) var activeSessions: Int = 0
@Published private(set) var networkStatus: NetworkStatus = .online

override init() {
workingChain = DWEnvironment.sharedInstance().currentChain.chainType
super.init()

networkStatusDidChange = { [weak self] state in
self?.updateNetworkState(newState: state)
}
NotificationCenter.default.publisher(for: NSNotification.Name.DWCurrentNetworkDidChange)
.sink { [weak self] _ in
DSLogger.log("[SW] CoinJoin: change of network to \(DWEnvironment.sharedInstance().currentChain.chainType.tag), resetting")
DSLogger.log("CoinJoin: change of network to \(DWEnvironment.sharedInstance().currentChain.chainType.tag), resetting")
self?.workingChain = DWEnvironment.sharedInstance().currentChain.chainType
self?.restoreMode()
}
.store(in: &permanentBag)

restoreMode()
startNetworkMonitoring()
}

func updateMode(mode: CoinJoinMode) async {
func updateMode(mode: CoinJoinMode, force: Bool = false) async {
self.coinJoinManager?.updateOptions(withEnabled: mode != .none)

if mode != .none && self.mode == .none {
if mode != .none && (force || self.currentMode == .none) {
configureMixing()
configureObservers()
} else if mode == .none {
Expand All @@ -139,8 +149,7 @@ class CoinJoinService: NSObject {

let account = DWEnvironment.sharedInstance().currentAccount
updateBalance(balance: account.balance)
let currentTimeSkew = await getCurrentTimeSkew()
updateState(mode: mode, timeSkew: currentTimeSkew, hasAnonymizableBalance: self.hasAnonymizableBalance, networkStatus: self.networkStatus, chain: DWEnvironment.sharedInstance().currentChain)
updateState(mode: mode, timeSkew: self.timeSkew, hasAnonymizableBalance: self.hasAnonymizableBalance, networkStatus: self.networkStatus, chain: DWEnvironment.sharedInstance().currentChain)
}

func updateTimeSkew(timeSkew: TimeInterval) {
Expand All @@ -159,7 +168,7 @@ class CoinJoinService: NSObject {
guard let coinJoinManager = self.coinJoinManager else { return }

if !coinJoinManager.startMixing() {
DSLogger.log("[SW] CoinJoin: Mixing has been started already.")
DSLogger.log("CoinJoin: Mixing has been started already.")
} else {
coinJoinManager.refreshUnusedKeys()
coinJoinManager.initMasternodeGroup()
Expand All @@ -172,7 +181,7 @@ class CoinJoinService: NSObject {

let account = DWEnvironment.sharedInstance().currentAccount
let rounds: Int32
switch mode {
switch currentMode {
case .none:
return
case .intermediate:
Expand Down Expand Up @@ -209,14 +218,14 @@ class CoinJoinService: NSObject {
guard let coinJoinManager = self.coinJoinManager else { return }

coinJoinManager.updateOptions(withAmount: balance)
DSLogger.log("[SW] CoinJoin: total balance: \(balance)")
DSLogger.log("CoinJoin: total balance: \(balance)")
let canDenominate = coinJoinManager.doAutomaticDenominating(withDryRun: true)

let coinJoinBalance = coinJoinManager.getBalance()
DSLogger.log("[SW] CoinJoin: mixed balance: \(coinJoinBalance.anonymized)")
DSLogger.log("CoinJoin: mixed balance: \(coinJoinBalance.anonymized)")

let anonBalance = coinJoinManager.getAnonymizableBalance(withSkipDenominated: false, skipUnconfirmed: false)
DSLogger.log("[SW] CoinJoin: anonymizable balance \(anonBalance)")
DSLogger.log("CoinJoin: anonymizable balance \(anonBalance)")

let smallestDenomination = coinJoinManager.getSmallestDenomination()
let hasPartiallyMixedCoins = (coinJoinBalance.denominatedTrusted - coinJoinBalance.anonymized) > 0
Expand All @@ -231,10 +240,10 @@ class CoinJoinService: NSObject {
hasBalanceLeftToMix = false
}

DSLogger.log("[SW] CoinJoin: can mix balance: \(hasBalanceLeftToMix) = balance: (\(anonBalance > smallestDenomination) && canDenominate: \(canDenominate)) || partially-mixed: \(hasPartiallyMixedCoins)")
DSLogger.log("CoinJoin: can mix balance: \(hasBalanceLeftToMix) = balance: (\(anonBalance > smallestDenomination) && canDenominate: \(canDenominate)) || partially-mixed: \(hasPartiallyMixedCoins)")

updateState(
mode: self.mode,
mode: self.currentMode,
timeSkew: self.timeSkew,
hasAnonymizableBalance: hasBalanceLeftToMix,
networkStatus: self.networkStatus,
Expand All @@ -259,11 +268,11 @@ class CoinJoinService: NSObject {
}

synchronized(self.updateMutex) {
DSLogger.log("[SW] CoinJoin: \(mode), \(timeSkew) s, \(hasAnonymizableBalance), \(networkStatus), synced: \(SyncingActivityMonitor.shared.state == .syncDone)")
DSLogger.log("CoinJoin: \(mode), \(timeSkew) s, \(hasAnonymizableBalance), \(networkStatus), synced: \(SyncingActivityMonitor.shared.state == .syncDone)")

self.networkStatus = networkStatus
self.hasAnonymizableBalance = hasAnonymizableBalance
self.mode = mode
self.currentMode = mode
self.timeSkew = timeSkew

if mode == .none || !isInsideTimeSkewBounds(timeSkew: timeSkew) || DWGlobalOptions.sharedInstance().isResyncingWallet {
Expand Down Expand Up @@ -293,12 +302,7 @@ class CoinJoinService: NSObject {
}

let previousMixingStatus = self.mixingState
DSLogger.log("[SW] CoinJoin: \(previousMixingStatus) -> \(state)")

if previousMixingStatus == .paused && state != .paused {
DSLogger.log("[SW] CoinJoin: moving from paused to \(state)")
}

DSLogger.log("CoinJoin: \(previousMixingStatus) -> \(state)")
self.mixingState = state

if state == .mixing && previousMixingStatus != .mixing {
Expand All @@ -314,7 +318,7 @@ class CoinJoinService: NSObject {

private func updateTimeSkewInternal(timeSkew: TimeInterval) {
let chain = DWEnvironment.sharedInstance().currentChain
updateState(mode: self.mode,
updateState(mode: self.currentMode,
timeSkew: timeSkew,
hasAnonymizableBalance: self.hasAnonymizableBalance,
networkStatus: self.networkStatus,
Expand All @@ -323,7 +327,7 @@ class CoinJoinService: NSObject {

private func getCurrentTimeSkew() async -> TimeInterval {
do {
return await TimeInterval(try TimeUtils.getTimeSkew())
return try await TimeUtils.getTimeSkew()
} catch {
DSLogger.log("[SW] CoinJoin: getTimeSkew problem: \(error)")
return 0.0
Expand All @@ -334,14 +338,9 @@ class CoinJoinService: NSObject {
self.stopMixing()
self.coinJoinManager = nil
self.hasAnonymizableBalance = false
let savedMode = self.savedMode
self.mode = .none
let restoredMode = CoinJoinMode(rawValue: savedMode) ?? .none

if restoredMode != .none {
Task {
await updateMode(mode: restoredMode)
}
Task {
await updateMode(mode: self.currentMode, force: true)
self.updateTimeSkewInternal(timeSkew: await getCurrentTimeSkew())
}
}

Expand Down Expand Up @@ -387,6 +386,11 @@ class CoinJoinService: NSObject {
SyncingActivityMonitor.shared.add(observer: self)
}

private func updateNetworkState(newState: NetworkStatus) {
self.networkStatus = newState
self.updateState(mode: mode, timeSkew: timeSkew, hasAnonymizableBalance: self.hasAnonymizableBalance, networkStatus: self.networkStatus, chain: DWEnvironment.sharedInstance().currentChain)
}

private func removeObservers() {
cancellableBag.forEach { $0.cancel() }
SyncingActivityMonitor.shared.remove(observer: self)
Expand All @@ -400,13 +404,9 @@ class CoinJoinService: NSObject {
}

extension CoinJoinService: DSCoinJoinManagerDelegate {
func sessionStarted(withId baseId: Int32, clientSessionId clientId: UInt256, denomination denom: UInt32, poolState state: PoolState, poolMessage message: PoolMessage, ipAddress address: UInt128, isJoined joined: Bool) {
updateActiveSessions()
}
func sessionStarted(withId baseId: Int32, clientSessionId clientId: UInt256, denomination denom: UInt32, poolState state: PoolState, poolMessage message: PoolMessage, ipAddress address: UInt128, isJoined joined: Bool) { }

func sessionComplete(withId baseId: Int32, clientSessionId clientId: UInt256, denomination denom: UInt32, poolState state: PoolState, poolMessage message: PoolMessage, ipAddress address: UInt128, isJoined joined: Bool) {
updateActiveSessions()
}
func sessionComplete(withId baseId: Int32, clientSessionId clientId: UInt256, denomination denom: UInt32, poolState state: PoolState, poolMessage message: PoolMessage, ipAddress address: UInt128, isJoined joined: Bool) { }

func mixingStarted() { }

Expand All @@ -429,23 +429,14 @@ extension CoinJoinService: DSCoinJoinManagerDelegate {
func transactionProcessed(withId txId: UInt256, type: CoinJoinTransactionType) {
self.updateProgress()
}

private func updateActiveSessions() {
guard let coinJoinManager = self.coinJoinManager else { return }

let activeSessions = coinJoinManager.getActiveSessionCount()
self.activeSessions = Int(activeSessions)

DSLogger.log("[SW] CoinJoin: Active sessions: \(activeSessions)")
}
}

extension CoinJoinService: SyncingActivityMonitorObserver {
func syncingActivityMonitorProgressDidChange(_ progress: Double) { }

func syncingActivityMonitorStateDidChange(previousState: SyncingActivityMonitor.State, state: SyncingActivityMonitor.State) {
self.updateState(
mode: self.mode,
mode: self.currentMode,
timeSkew: self.timeSkew,
hasAnonymizableBalance: self.hasAnonymizableBalance,
networkStatus: self.networkStatus,
Expand Down
Loading

0 comments on commit 15fde64

Please sign in to comment.