From 764d60dc7e7cdeb0303ec4b91b18a32cb5bb20e3 Mon Sep 17 00:00:00 2001 From: Andrei Ashikhmin Date: Fri, 27 Sep 2024 14:47:53 +0700 Subject: [PATCH 1/3] feat: network switching --- DashWallet.xcodeproj/project.pbxproj | 14 ++- .../Models/CoinJoin/CoinJoinProgress.swift | 22 ++++ .../Models/CoinJoin/CoinJoinService.swift | 102 ++++++++++++------ .../Transactions/Model/Transaction.swift | 6 -- .../CoinJoinLevelsViewController.swift | 2 +- .../DashPay/CoinJoin/CoinJoinViewModel.swift | 13 --- .../Sources/UI/Home/Views/HomeViewModel.swift | 6 +- .../Settings/SettingsMenuViewController.swift | 18 +--- .../UI/Menu/Settings/SettingsViewModel.swift | 10 +- .../Amount/Model/Send/SendAmountModel.swift | 6 +- .../PaymentModels/DWPaymentProcessor.m | 2 +- 11 files changed, 122 insertions(+), 79 deletions(-) create mode 100644 DashWallet/Sources/Models/CoinJoin/CoinJoinProgress.swift diff --git a/DashWallet.xcodeproj/project.pbxproj b/DashWallet.xcodeproj/project.pbxproj index 3ca502a2e..c9db0e96c 100644 --- a/DashWallet.xcodeproj/project.pbxproj +++ b/DashWallet.xcodeproj/project.pbxproj @@ -554,6 +554,8 @@ 753130922B47EE920069C9B7 /* UpholdCapability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 753130902B47EE920069C9B7 /* UpholdCapability.swift */; }; 753130972B4944130069C9B7 /* UpholdError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 753130962B4944130069C9B7 /* UpholdError.swift */; }; 753130982B4944130069C9B7 /* UpholdError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 753130962B4944130069C9B7 /* UpholdError.swift */; }; + 753FD7E22CA44BDD00B7751F /* CoinJoinProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 753FD7E12CA44BDD00B7751F /* CoinJoinProgress.swift */; }; + 753FD7E32CA44BDD00B7751F /* CoinJoinProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 753FD7E12CA44BDD00B7751F /* CoinJoinProgress.swift */; }; 753FDBEA2AEA422F0005EEC3 /* VotingPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 753FDBE92AEA422F0005EEC3 /* VotingPrefs.swift */; }; 753FDBEC2AECF4CC0005EEC3 /* VotingHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 753FDBEB2AECF4CC0005EEC3 /* VotingHeaderView.xib */; }; 753FDBEE2AECF52B0005EEC3 /* UsernameVoting.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 753FDBED2AECF52B0005EEC3 /* UsernameVoting.storyboard */; }; @@ -2435,6 +2437,7 @@ 7531308C2B47EC910069C9B7 /* UpholdClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpholdClient.swift; sourceTree = ""; }; 753130902B47EE920069C9B7 /* UpholdCapability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpholdCapability.swift; sourceTree = ""; }; 753130962B4944130069C9B7 /* UpholdError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpholdError.swift; sourceTree = ""; }; + 753FD7E12CA44BDD00B7751F /* CoinJoinProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoinJoinProgress.swift; sourceTree = ""; }; 753FDBE92AEA422F0005EEC3 /* VotingPrefs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VotingPrefs.swift; sourceTree = ""; }; 753FDBEB2AECF4CC0005EEC3 /* VotingHeaderView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = VotingHeaderView.xib; sourceTree = ""; }; 753FDBED2AECF52B0005EEC3 /* UsernameVoting.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = UsernameVoting.storyboard; sourceTree = ""; }; @@ -6013,6 +6016,7 @@ isa = PBXGroup; children = ( 7503643D2C89D49A0029EC0D /* CoinJoinService.swift */, + 753FD7E12CA44BDD00B7751F /* CoinJoinProgress.swift */, ); path = CoinJoin; sourceTree = ""; @@ -8811,6 +8815,7 @@ 754BEA122C0B6BD700E8C93C /* HomeViewModel.swift in Sources */, 2A4430E722CBB6EC009BAF7F /* AppDelegate.m in Sources */, C917023F29D44E0B008C034D /* SendReceivePageController.swift in Sources */, + 753FD7E22CA44BDD00B7751F /* CoinJoinProgress.swift in Sources */, 2A7A7BD92348CB7300451078 /* DWSettingsMenuModel.m in Sources */, 478A2C7228DC909C00AD1420 /* BaseNavigationController.swift in Sources */, 47CDEECC294A2BAD008AE06D /* UIViewController+Coinbase.swift in Sources */, @@ -9418,6 +9423,7 @@ C943B4F52A40A54600AF23C5 /* DWDPIncomingRequestObject.m in Sources */, C943B4BA2A40A54600AF23C5 /* DWRequestsModel.m in Sources */, C9D2C7982A320AA000D15901 /* BaseResponse.swift in Sources */, + 753FD7E32CA44BDD00B7751F /* CoinJoinProgress.swift in Sources */, C9D2C7992A320AA000D15901 /* DWDemoAdvancedSecurityViewController.m in Sources */, C943B3212A408CED00AF23C5 /* DWImgurItemView.m in Sources */, C9D2C79C2A320AA000D15901 /* TxWithinTimePeriod.swift in Sources */, @@ -10747,7 +10753,7 @@ CLIENT_ID = 0c38beb67db0c68191326be347d7ec0abd7d77adb02a79db1abeba343f16a0f7; CLIENT_SECRET = cc980185754f905e24250f877792817c03540b3d0e0959721df291c816797e59; CODE_SIGN_ENTITLEMENTS = dashwallet/dashwallet.entitlements; - CURRENT_PROJECT_VERSION = 165; + CURRENT_PROJECT_VERSION = 169; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; @@ -10883,7 +10889,7 @@ CLIENT_ID = 0c38beb67db0c68191326be347d7ec0abd7d77adb02a79db1abeba343f16a0f7; CLIENT_SECRET = cc980185754f905e24250f877792817c03540b3d0e0959721df291c816797e59; CODE_SIGN_ENTITLEMENTS = dashwallet/dashwallet.entitlements; - CURRENT_PROJECT_VERSION = 165; + CURRENT_PROJECT_VERSION = 169; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -11018,7 +11024,7 @@ CLIENT_ID = 0c38beb67db0c68191326be347d7ec0abd7d77adb02a79db1abeba343f16a0f7; CLIENT_SECRET = cc980185754f905e24250f877792817c03540b3d0e0959721df291c816797e59; CODE_SIGN_ENTITLEMENTS = dashwallet/dashwallet.entitlements; - CURRENT_PROJECT_VERSION = 165; + CURRENT_PROJECT_VERSION = 169; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -11163,7 +11169,7 @@ CLIENT_ID = 0c38beb67db0c68191326be347d7ec0abd7d77adb02a79db1abeba343f16a0f7; CLIENT_SECRET = cc980185754f905e24250f877792817c03540b3d0e0959721df291c816797e59; CODE_SIGN_ENTITLEMENTS = dashwallet/dashwallet.entitlements; - CURRENT_PROJECT_VERSION = 165; + CURRENT_PROJECT_VERSION = 169; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; GCC_PRECOMPILE_PREFIX_HEADER = YES; diff --git a/DashWallet/Sources/Models/CoinJoin/CoinJoinProgress.swift b/DashWallet/Sources/Models/CoinJoin/CoinJoinProgress.swift new file mode 100644 index 000000000..7bb34005d --- /dev/null +++ b/DashWallet/Sources/Models/CoinJoin/CoinJoinProgress.swift @@ -0,0 +1,22 @@ +// +// Created by Andrei Ashikhmin +// Copyright © 2024 Dash Core Group. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +struct CoinJoinProgress: Equatable { + let progress: Double + let totalBalance: UInt64 + let coinJoinBalance: UInt64 +} diff --git a/DashWallet/Sources/Models/CoinJoin/CoinJoinService.swift b/DashWallet/Sources/Models/CoinJoin/CoinJoinService.swift index 9f3a60044..455e134dd 100644 --- a/DashWallet/Sources/Models/CoinJoin/CoinJoinService.swift +++ b/DashWallet/Sources/Models/CoinJoin/CoinJoinService.swift @@ -60,13 +60,15 @@ private let kDefaultRounds: Int32 = 4 private let kDefaultSessions: Int32 = 6 private let kDefaultDenominationGoal: Int32 = 50 private let kDefaultDenominationHardcap: Int32 = 300 -private let kCoinJoinMode = "coinJoinModeKey" +private let kCoinJoinMainnetMode = "coinJoinModeMainnetKey" +private let kCoinJoinTestnetMode = "coinJoinModeTestnetKey" class CoinJoinService: NSObject { static let shared: CoinJoinService = { return CoinJoinService() }() + private var permanentBag = Set() private var cancellableBag = Set() private let updateMutex = NSLock() private let updateMixingStateMutex = NSLock() @@ -74,13 +76,18 @@ class CoinJoinService: NSObject { private var hasAnonymizableBalance: Bool = false private var networkStatus: NetworkStatus = .online - private var _savedMode: Int? = nil + private var chainModeKey: String { + get { + DWEnvironment.sharedInstance().currentChain.isMainnet() ? kCoinJoinMainnetMode : kCoinJoinTestnetMode + } + } + private var savedMode: Int { - get { _savedMode ?? UserDefaults.standard.integer(forKey: kCoinJoinMode) } - set(value) { - _savedMode = value - UserDefaults.standard.set(value, forKey: kCoinJoinMode) + get { + let key = chainModeKey + return UserDefaults.standard.integer(forKey: key) } + set(value) { UserDefaults.standard.set(value, forKey: chainModeKey) } } @Published private(set) var mode: CoinJoinMode = .none { @@ -90,23 +97,20 @@ class CoinJoinService: NSObject { } @Published var mixingState: MixingStatus = .notStarted - @Published private(set) var progress: Double = 0.0 - @Published private(set) var totalBalance: UInt64 = 0 - @Published private(set) var coinJoinBalance: UInt64 = 0 + @Published private(set) var progress = CoinJoinProgress(progress: 0.0, totalBalance: 0, coinJoinBalance: 0) @Published private(set) var activeSessions: Int = 0 override init() { super.init() - NotificationCenter.default.publisher(for: NSNotification.Name.DSWalletBalanceDidChange) - .sink { [weak self] _ in self?.updateBalance(balance: DWEnvironment.sharedInstance().currentAccount.balance) } - .store(in: &cancellableBag) - - let mode = CoinJoinMode(rawValue: savedMode) ?? .none + NotificationCenter.default.publisher(for: NSNotification.Name.DWCurrentNetworkDidChange) + .sink { [weak self] _ in + self?.coinJoinManager = nil + self?.restoreMode() + } + .store(in: &permanentBag) - if mode != .none { - updateMode(mode: mode) - } + restoreMode() } func updateMode(mode: CoinJoinMode) { @@ -114,8 +118,11 @@ class CoinJoinService: NSObject { let account = DWEnvironment.sharedInstance().currentAccount let balance = account.balance - if (mode != .none && self.mode == .none) { + if mode != .none && self.mode == .none { configureMixing(amount: balance) + configureObservers() + } else if mode == .none { + cancellableBag.removeAll() } updateBalance(balance: balance) @@ -126,6 +133,7 @@ class CoinJoinService: NSObject { private func prepareMixing() { guard let coinJoinManager = self.coinJoinManager ?? createCoinJoinManager() else { return } + coinJoinManager.managerDelegate = self coinJoinManager.setStopOnNothingToDo(true) coinJoinManager.start() } @@ -170,9 +178,7 @@ class CoinJoinService: NSObject { let anonymizedBalance = coinJoinBalance.anonymized DispatchQueue.main.async { - self.progress = progress - self.totalBalance = totalBalance - self.coinJoinBalance = anonymizedBalance + self.progress = CoinJoinProgress(progress: progress, totalBalance: totalBalance, coinJoinBalance: anonymizedBalance) } } } @@ -283,6 +289,42 @@ class CoinJoinService: NSObject { } } } + + private func restoreMode() { + let mode = CoinJoinMode(rawValue: savedMode) ?? .none + + if mode != self.mode { + updateMode(mode: mode) + } + } + + private func configureObservers() { + NotificationCenter.default.publisher(for: NSNotification.Name.DSWalletBalanceDidChange) + .sink { [weak self] _ in + self?.updateBalance(balance: DWEnvironment.sharedInstance().currentAccount.balance) + } + .store(in: &cancellableBag) + + NotificationCenter.default.publisher(for: NSNotification.Name.DSChainManagerSyncStateDidChange) + .sink { [weak self] _ in + guard let self = self else { return } + self.updateState( + balance: DWEnvironment.sharedInstance().currentAccount.balance, + mode: self.mode, + timeSkew: TimeInterval(0), // TODO + hasAnonymizableBalance: self.hasAnonymizableBalance, + networkStatus: self.networkStatus, + chain: DWEnvironment.sharedInstance().currentChain + ) + } + .store(in: &cancellableBag) + } + + private func synchronized(_ lock: NSLock, closure: () -> Void) { + lock.lock() + defer { lock.unlock() } + closure() + } } extension CoinJoinService: DSCoinJoinManagerDelegate { @@ -296,11 +338,17 @@ extension CoinJoinService: DSCoinJoinManagerDelegate { func mixingStarted() { } - func mixingComplete(_ withError: Bool) { + func mixingComplete(_ withError: Bool, isInterrupted: Bool) { + if isInterrupted { + DSLogger.log("[SW] CoinJoin: Mixing Interrupted. \(progress)") + updateMixingState(state: .notStarted) + return + } + if withError { - DSLogger.log("[SW] CoinJoin: Mixing Error. \(progress)% mixed") + DSLogger.log("[SW] CoinJoin: Mixing Error. \(progress)") } else { - DSLogger.log("[SW] CoinJoin: Mixing Complete. \(progress)% mixed") + DSLogger.log("[SW] CoinJoin: Mixing Complete. \(progress)") } self.updateMixingState(state: withError ? .error : .finished) // TODO: paused? @@ -318,11 +366,5 @@ extension CoinJoinService: DSCoinJoinManagerDelegate { DSLogger.log("[SW] CoinJoin: Active sessions: \(activeSessions)") } - - private func synchronized(_ lock: NSLock, closure: () -> Void) { - lock.lock() - defer { lock.unlock() } - closure() - } } diff --git a/DashWallet/Sources/Models/Transactions/Model/Transaction.swift b/DashWallet/Sources/Models/Transactions/Model/Transaction.swift index c3885496b..40e1af619 100644 --- a/DashWallet/Sources/Models/Transactions/Model/Transaction.swift +++ b/DashWallet/Sources/Models/Transactions/Model/Transaction.swift @@ -199,12 +199,6 @@ extension Transaction { tx.txHashData } - var currentBlockHeight: UInt64 { - let chain = DWEnvironment.sharedInstance().currentChain - let lastHeight = chain.lastTerminalBlockHeight - return UInt64(lastHeight) - } - var isCoinbaseTransaction: Bool { tx is DSCoinbaseTransaction } diff --git a/DashWallet/Sources/UI/DashPay/CoinJoin/CoinJoinLevelsViewController.swift b/DashWallet/Sources/UI/DashPay/CoinJoin/CoinJoinLevelsViewController.swift index 37140d0a1..ab17aad16 100644 --- a/DashWallet/Sources/UI/DashPay/CoinJoin/CoinJoinLevelsViewController.swift +++ b/DashWallet/Sources/UI/DashPay/CoinJoin/CoinJoinLevelsViewController.swift @@ -101,7 +101,7 @@ extension CoinJoinLevelsViewController { return } - if viewModel.selectedMode == .none { + if viewModel.selectedMode == .none || viewModel.mixingState == .notStarted { viewModel.selectedMode = mode } else { confirmFor(mode) diff --git a/DashWallet/Sources/UI/DashPay/CoinJoin/CoinJoinViewModel.swift b/DashWallet/Sources/UI/DashPay/CoinJoin/CoinJoinViewModel.swift index 67f5e9408..d2e8038bd 100644 --- a/DashWallet/Sources/UI/DashPay/CoinJoin/CoinJoinViewModel.swift +++ b/DashWallet/Sources/UI/DashPay/CoinJoin/CoinJoinViewModel.swift @@ -35,9 +35,6 @@ class CoinJoinViewModel: ObservableObject { @Published var selectedMode: CoinJoinMode = .none @Published private(set) var mixingState: MixingStatus = .notStarted - @Published private(set) var progress: Double = 0.0 - @Published private(set) var totalBalance: UInt64 = 0 - @Published private(set) var coinJoinBalance: UInt64 = 0 private var _infoShown: Bool? = nil var infoShown: Bool { @@ -62,16 +59,6 @@ class CoinJoinViewModel: ObservableObject { self?.mixingState = state } .store(in: &cancellableBag) - - coinJoinService.$progress - .receive(on: DispatchQueue.main) - .sink { [weak self] progress in - guard let self = self else { return } - self.progress = progress - self.totalBalance = coinJoinService.totalBalance - self.coinJoinBalance = coinJoinService.coinJoinBalance - } - .store(in: &cancellableBag) } func startMixing() { diff --git a/DashWallet/Sources/UI/Home/Views/HomeViewModel.swift b/DashWallet/Sources/UI/Home/Views/HomeViewModel.swift index 4ad97c71c..ecb2b535f 100644 --- a/DashWallet/Sources/UI/Home/Views/HomeViewModel.swift +++ b/DashWallet/Sources/UI/Home/Views/HomeViewModel.swift @@ -123,9 +123,9 @@ extension HomeViewModel { title: NSLocalizedString("Mixing", comment: "CoinJoin"), isOn: coinJoinService.mixingState.isInProgress, state: coinJoinService.mixingState, - progress: coinJoinService.progress, - mixed: Double(coinJoinService.coinJoinBalance) / Double(DUFFS), - total: Double(coinJoinService.totalBalance) / Double(DUFFS) + progress: coinJoinService.progress.progress, + mixed: Double(coinJoinService.progress.coinJoinBalance) / Double(DUFFS), + total: Double(coinJoinService.progress.totalBalance) / Double(DUFFS) ) } } diff --git a/DashWallet/Sources/UI/Menu/Settings/SettingsMenuViewController.swift b/DashWallet/Sources/UI/Menu/Settings/SettingsMenuViewController.swift index d97dbbf76..eaf18d330 100644 --- a/DashWallet/Sources/UI/Menu/Settings/SettingsMenuViewController.swift +++ b/DashWallet/Sources/UI/Menu/Settings/SettingsMenuViewController.swift @@ -48,18 +48,7 @@ class SettingsMenuViewController: UIViewController, DWLocalCurrencyViewControlle view.backgroundColor = .dw_secondaryBackground() - let content = SettingsMenuContent( - viewModel: self.viewModel, - onLocalCurrencyChange: { [weak self] in - self?.showCurrencySelector() - }, - onNetworkChange: { [weak self] in - self?.showChangeNetwork() - }, - onRescanBlockchain: { [weak self] in - self?.showWarningAboutReclassifiedTransactions() - } - ) + let content = SettingsMenuContent(viewModel: self.viewModel) let swiftUIController = UIHostingController(rootView: content) swiftUIController.view.backgroundColor = .dw_secondaryBackground() dw_embedChild(swiftUIController) @@ -206,6 +195,8 @@ class SettingsMenuViewController: UIViewController, DWLocalCurrencyViewControlle } private func updateView() { + cancellables.removeAll() + viewModel.resetNavigation() // Trigger a view update viewDidLoad() } @@ -229,9 +220,6 @@ extension SettingsMenuViewController { struct SettingsMenuContent: View { @StateObject var viewModel: SettingsViewModel - var onLocalCurrencyChange: () -> Void - var onNetworkChange: () -> Void - var onRescanBlockchain: () -> Void var body: some View { List(viewModel.items) { item in diff --git a/DashWallet/Sources/UI/Menu/Settings/SettingsViewModel.swift b/DashWallet/Sources/UI/Menu/Settings/SettingsViewModel.swift index 40da83171..22ba9b187 100644 --- a/DashWallet/Sources/UI/Menu/Settings/SettingsViewModel.swift +++ b/DashWallet/Sources/UI/Menu/Settings/SettingsViewModel.swift @@ -39,6 +39,10 @@ class SettingsViewModel: ObservableObject { setupCoinJoinObservers() } + func resetNavigation() { + self.navigationDestination = .none + } + private func setupCoinJoinObservers() { coinJoinService.$progress .removeDuplicates() @@ -113,9 +117,9 @@ class SettingsViewModel: ObservableObject { title: NSLocalizedString("CoinJoin", comment: "CoinJoin"), isOn: coinJoinService.mode != .none, state: coinJoinService.mixingState, - progress: coinJoinService.progress, - mixed: Double(coinJoinService.coinJoinBalance) / Double(DUFFS), - total: Double(coinJoinService.totalBalance) / Double(DUFFS), + progress: coinJoinService.progress.progress, + mixed: Double(coinJoinService.progress.coinJoinBalance) / Double(DUFFS), + total: Double(coinJoinService.progress.totalBalance) / Double(DUFFS), action: { [weak self] in self?.navigationDestination = .coinjoin } diff --git a/DashWallet/Sources/UI/Payments/Amount/Model/Send/SendAmountModel.swift b/DashWallet/Sources/UI/Payments/Amount/Model/Send/SendAmountModel.swift index 87d0d1330..d622904d3 100644 --- a/DashWallet/Sources/UI/Payments/Amount/Model/Send/SendAmountModel.swift +++ b/DashWallet/Sources/UI/Payments/Amount/Model/Send/SendAmountModel.swift @@ -72,10 +72,10 @@ class SendAmountModel: BaseAmountModel { checkAmountForErrors() if CoinJoinService.shared.mode != .none { - CoinJoinService.shared.$coinJoinBalance + CoinJoinService.shared.$progress .removeDuplicates() - .sink { [weak self] balance in - self?.coinJoinBalance = balance + .sink { [weak self] progress in + self?.coinJoinBalance = progress.coinJoinBalance } .store(in: &cancellableBag) } diff --git a/DashWallet/Sources/UI/Payments/PaymentModels/DWPaymentProcessor.m b/DashWallet/Sources/UI/Payments/PaymentModels/DWPaymentProcessor.m index 99aeee9ed..b7e2ca72b 100644 --- a/DashWallet/Sources/UI/Payments/PaymentModels/DWPaymentProcessor.m +++ b/DashWallet/Sources/UI/Payments/PaymentModels/DWPaymentProcessor.m @@ -323,7 +323,7 @@ - (void)confirmProtocolRequest:(DSPaymentProtocolRequest *)protocolRequest { const BOOL addressIsFromPasteboard = self.paymentInput.source == DWPaymentInputSource_Pasteboard; self.didSendRequestDelegateNotified = NO; - + [chainManager.transactionManager confirmProtocolRequest:protocolRequest forAmount:self.amount From 42fc7ce5a2fdd8075fbc49cf3ddb6a91a28f63a5 Mon Sep 17 00:00:00 2001 From: Andrei Ashikhmin Date: Sat, 28 Sep 2024 13:25:06 +0700 Subject: [PATCH 2/3] fix: use standard wallet way of detecting sync status --- DashWallet.xcodeproj/project.pbxproj | 8 ++-- .../Models/CoinJoin/CoinJoinService.swift | 44 +++++++++++-------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/DashWallet.xcodeproj/project.pbxproj b/DashWallet.xcodeproj/project.pbxproj index c9db0e96c..155dbd6f1 100644 --- a/DashWallet.xcodeproj/project.pbxproj +++ b/DashWallet.xcodeproj/project.pbxproj @@ -10753,7 +10753,7 @@ CLIENT_ID = 0c38beb67db0c68191326be347d7ec0abd7d77adb02a79db1abeba343f16a0f7; CLIENT_SECRET = cc980185754f905e24250f877792817c03540b3d0e0959721df291c816797e59; CODE_SIGN_ENTITLEMENTS = dashwallet/dashwallet.entitlements; - CURRENT_PROJECT_VERSION = 169; + CURRENT_PROJECT_VERSION = 170; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; @@ -10889,7 +10889,7 @@ CLIENT_ID = 0c38beb67db0c68191326be347d7ec0abd7d77adb02a79db1abeba343f16a0f7; CLIENT_SECRET = cc980185754f905e24250f877792817c03540b3d0e0959721df291c816797e59; CODE_SIGN_ENTITLEMENTS = dashwallet/dashwallet.entitlements; - CURRENT_PROJECT_VERSION = 169; + CURRENT_PROJECT_VERSION = 170; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -11024,7 +11024,7 @@ CLIENT_ID = 0c38beb67db0c68191326be347d7ec0abd7d77adb02a79db1abeba343f16a0f7; CLIENT_SECRET = cc980185754f905e24250f877792817c03540b3d0e0959721df291c816797e59; CODE_SIGN_ENTITLEMENTS = dashwallet/dashwallet.entitlements; - CURRENT_PROJECT_VERSION = 169; + CURRENT_PROJECT_VERSION = 170; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -11169,7 +11169,7 @@ CLIENT_ID = 0c38beb67db0c68191326be347d7ec0abd7d77adb02a79db1abeba343f16a0f7; CLIENT_SECRET = cc980185754f905e24250f877792817c03540b3d0e0959721df291c816797e59; CODE_SIGN_ENTITLEMENTS = dashwallet/dashwallet.entitlements; - CURRENT_PROJECT_VERSION = 169; + CURRENT_PROJECT_VERSION = 170; DEVELOPMENT_TEAM = 44RJ69WHFF; EXCLUDED_ARCHS = ""; GCC_PRECOMPILE_PREFIX_HEADER = YES; diff --git a/DashWallet/Sources/Models/CoinJoin/CoinJoinService.swift b/DashWallet/Sources/Models/CoinJoin/CoinJoinService.swift index 455e134dd..8659804ca 100644 --- a/DashWallet/Sources/Models/CoinJoin/CoinJoinService.swift +++ b/DashWallet/Sources/Models/CoinJoin/CoinJoinService.swift @@ -122,7 +122,7 @@ class CoinJoinService: NSObject { configureMixing(amount: balance) configureObservers() } else if mode == .none { - cancellableBag.removeAll() + removeObservers() } updateBalance(balance: balance) @@ -146,9 +146,7 @@ class CoinJoinService: NSObject { } else { coinJoinManager.refreshUnusedKeys() coinJoinManager.initMasternodeGroup() - coinJoinManager.doAutomaticDenominating() - - DSLogger.log("[SW] CoinJoin: Mixing \(coinJoinManager.startMixing() ? "started successfully" : "start failed, will retry")") // TODO: failed statuses: \(coinJoinManager.statuses) + coinJoinManager.doAutomaticDenominating(withReport: true) } } @@ -241,7 +239,7 @@ class CoinJoinService: NSObject { chain: DSChain ) { synchronized(self.updateMutex) { - DSLogger.log("[SW] CoinJoin: \(mode), \(timeSkew) ms, \(hasAnonymizableBalance), \(networkStatus), synced: \(chain.chainManager!.isSynced)") + DSLogger.log("[SW] CoinJoin: \(mode), \(timeSkew) ms, \(hasAnonymizableBalance), \(networkStatus), synced: \(SyncingActivityMonitor.shared.state == .syncDone)") self.networkStatus = networkStatus self.hasAnonymizableBalance = hasAnonymizableBalance @@ -254,7 +252,7 @@ class CoinJoinService: NSObject { configureMixing(amount: balance) if hasAnonymizableBalance { - if networkStatus == .online && chain.chainManager!.isSynced { + if networkStatus == .online && SyncingActivityMonitor.shared.state == .syncDone { updateMixingState(state: .mixing) } else { updateMixingState(state: .paused) @@ -305,19 +303,12 @@ class CoinJoinService: NSObject { } .store(in: &cancellableBag) - NotificationCenter.default.publisher(for: NSNotification.Name.DSChainManagerSyncStateDidChange) - .sink { [weak self] _ in - guard let self = self else { return } - self.updateState( - balance: DWEnvironment.sharedInstance().currentAccount.balance, - mode: self.mode, - timeSkew: TimeInterval(0), // TODO - hasAnonymizableBalance: self.hasAnonymizableBalance, - networkStatus: self.networkStatus, - chain: DWEnvironment.sharedInstance().currentChain - ) - } - .store(in: &cancellableBag) + SyncingActivityMonitor.shared.add(observer: self) + } + + private func removeObservers() { + cancellableBag.removeAll() + SyncingActivityMonitor.shared.remove(observer: self) } private func synchronized(_ lock: NSLock, closure: () -> Void) { @@ -368,3 +359,18 @@ extension CoinJoinService: DSCoinJoinManagerDelegate { } } +extension CoinJoinService: SyncingActivityMonitorObserver { + func syncingActivityMonitorProgressDidChange(_ progress: Double) { } + + func syncingActivityMonitorStateDidChange(previousState: SyncingActivityMonitor.State, state: SyncingActivityMonitor.State) { + + self.updateState( + balance: DWEnvironment.sharedInstance().currentAccount.balance, + mode: self.mode, + timeSkew: TimeInterval(0), // TODO + hasAnonymizableBalance: self.hasAnonymizableBalance, + networkStatus: self.networkStatus, + chain: DWEnvironment.sharedInstance().currentChain + ) + } +} From 4d6fe669c639d4ba051e856b7894317f7127abd0 Mon Sep 17 00:00:00 2001 From: Andrei Ashikhmin Date: Wed, 2 Oct 2024 16:23:02 +0700 Subject: [PATCH 3/3] fix: recheck chain explicitelly in case chain switch notification didn't fire --- .../Models/CoinJoin/CoinJoinService.swift | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/DashWallet/Sources/Models/CoinJoin/CoinJoinService.swift b/DashWallet/Sources/Models/CoinJoin/CoinJoinService.swift index 8659804ca..8569fed84 100644 --- a/DashWallet/Sources/Models/CoinJoin/CoinJoinService.swift +++ b/DashWallet/Sources/Models/CoinJoin/CoinJoinService.swift @@ -75,7 +75,8 @@ class CoinJoinService: NSObject { private var coinJoinManager: DSCoinJoinManager? = nil private var hasAnonymizableBalance: Bool = false private var networkStatus: NetworkStatus = .online - + private var workingChain: ChainType + private var chainModeKey: String { get { DWEnvironment.sharedInstance().currentChain.isMainnet() ? kCoinJoinMainnetMode : kCoinJoinTestnetMode @@ -101,11 +102,13 @@ class CoinJoinService: NSObject { @Published private(set) var activeSessions: Int = 0 override init() { + workingChain = DWEnvironment.sharedInstance().currentChain.chainType super.init() NotificationCenter.default.publisher(for: NSNotification.Name.DWCurrentNetworkDidChange) .sink { [weak self] _ in - self?.coinJoinManager = nil + DSLogger.log("[SW] CoinJoin: change of network to \(DWEnvironment.sharedInstance().currentChain.chainType.tag), resetting") + self?.workingChain = DWEnvironment.sharedInstance().currentChain.chainType self?.restoreMode() } .store(in: &permanentBag) @@ -182,7 +185,7 @@ class CoinJoinService: NSObject { } private func createCoinJoinManager() -> DSCoinJoinManager? { - self.coinJoinManager = DSCoinJoinManager.sharedInstance(for: DWEnvironment().currentChain) + self.coinJoinManager = DSCoinJoinManager.sharedInstance(for: DWEnvironment.sharedInstance().currentChain) coinJoinManager?.managerDelegate = self return self.coinJoinManager } @@ -238,6 +241,10 @@ class CoinJoinService: NSObject { networkStatus: NetworkStatus, chain: DSChain ) { + if !recheckCurrentChain() { + return + } + synchronized(self.updateMutex) { DSLogger.log("[SW] CoinJoin: \(mode), \(timeSkew) ms, \(hasAnonymizableBalance), \(networkStatus), synced: \(SyncingActivityMonitor.shared.state == .syncDone)") @@ -289,11 +296,12 @@ class CoinJoinService: NSObject { } private func restoreMode() { + self.stopMixing() + self.coinJoinManager = nil + self.hasAnonymizableBalance = false + self.mode = .none let mode = CoinJoinMode(rawValue: savedMode) ?? .none - - if mode != self.mode { - updateMode(mode: mode) - } + updateMode(mode: mode) } private func configureObservers() { @@ -357,13 +365,25 @@ extension CoinJoinService: DSCoinJoinManagerDelegate { DSLogger.log("[SW] CoinJoin: Active sessions: \(activeSessions)") } + + private func recheckCurrentChain() -> Bool { + let chainType = DWEnvironment.sharedInstance().currentChain.chainType + + if self.workingChain.tag != chainType.tag { + DSLogger.log("[SW] CoinJoin: reset chain after recheck to type \(chainType.tag)") + self.workingChain = chainType + restoreMode() + return false + } + + return true + } } extension CoinJoinService: SyncingActivityMonitorObserver { func syncingActivityMonitorProgressDidChange(_ progress: Double) { } func syncingActivityMonitorStateDidChange(previousState: SyncingActivityMonitor.State, state: SyncingActivityMonitor.State) { - self.updateState( balance: DWEnvironment.sharedInstance().currentAccount.balance, mode: self.mode,