Skip to content

Commit

Permalink
fix(dashpay): improve timeskew handling for CoinJoin
Browse files Browse the repository at this point in the history
  • Loading branch information
HashEngineering committed Feb 15, 2024
1 parent c904b14 commit 27bdd70
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 14 deletions.
2 changes: 2 additions & 0 deletions wallet/res/values/strings-extra.xml
Original file line number Diff line number Diff line change
Expand Up @@ -697,4 +697,6 @@
<string name="masternode_key_not_used">Not used</string>
<string name="masternode_key_revoked">Revoked</string>
<string name="masternode_key_private_public_base64">Private / Public Keys (base64)</string>
<string name="timeskew_ahead">ahead</string>
<string name="timeskew_behind">behind</string>
</resources>
2 changes: 1 addition & 1 deletion wallet/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
<string name="wallet_low_storage_dialog_button_apps">Manage apps</string>
<string name="wallet_timeskew_dialog_title">Check date &amp; time settings</string>
<string name="wallet_timeskew_dialog_msg">Your device time is off by %d minutes. You probably cannot send or receive Dash due to this problem.\n\nYou should check and if necessary correct your date, time and timezone settings.</string>
<string name="wallet_coinjoin_timeskew_dialog_msg">Your device time is off by %d seconds. You cannot use CoinJoin due to this problem.\n\nThe time settings on your device needs to be changed to “Set time automatically” to use CoinJoin.</string>
<string name="wallet_coinjoin_timeskew_dialog_msg">Your device time is %s by %d seconds. You cannot use CoinJoin due to this problem.\n\nThe time settings on your device needs to be changed to “Set time automatically” to use CoinJoin.</string>
<string name="settings_coinjoin_timeskew_dialog_msg">Your device time is off by more than 2 seconds. You cannot use CoinJoin due to this problem.\n\nThe time settings on your device needs to be changed to “Set time automatically” before using CoinJoin.</string>
<string name="send_coins_activity_title">Send Dash</string>
<string name="send_coins_fragment_request_payment_request_progress">Fetching signature from %s…</string>
Expand Down
17 changes: 13 additions & 4 deletions wallet/src/de/schildbach/wallet/service/CoinJoinService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,19 @@ class CoinJoinMixingService @Inject constructor(
const val DEFAULT_SESSIONS = 4
const val DEFAULT_DENOMINATIONS_GOAL = 50
const val DEFAULT_DENOMINATIONS_HARDCAP = 300
const val MAX_ALLOWED_TIMESKEW = 4000L // 4 seconds
const val MAX_ALLOWED_AHEAD_TIMESKEW = 5000L // 5 seconds
const val MAX_ALLOWED_BEHIND_TIMESKEW = 20000L // 20 seconds

// these are not for production
val FAST_MIXING_DENOMINATIONS_REMOVE = listOf<Denomination>() // Denomination.THOUSANDTH)
val FAST_MIXING_DENOMINATIONS_REMOVE = listOf<Denomination>() // Denomination.THOUSANDTH

fun isInsideTimeSkewBounds(timeSkew: Long): Boolean {
return if (timeSkew > 0) {
timeSkew < MAX_ALLOWED_AHEAD_TIMESKEW
} else {
(-timeSkew) < MAX_ALLOWED_BEHIND_TIMESKEW
}
}
}

private val coinJoinManager: CoinJoinManager?
Expand Down Expand Up @@ -148,7 +157,7 @@ class CoinJoinMixingService @Inject constructor(
private var networkStatus: NetworkStatus = NetworkStatus.UNKNOWN
private var isSynced = false
private var hasAnonymizableBalance: Boolean = false
private var timeSkew: Long = Long.MIN_VALUE
private var timeSkew: Long = 0L

// https://stackoverflow.com/questions/55421710/how-to-suspend-kotlin-coroutine-until-notified
private val updateMutex = Mutex(locked = false)
Expand Down Expand Up @@ -292,7 +301,7 @@ class CoinJoinMixingService @Inject constructor(
this.mode = mode
this.timeSkew = timeSkew

if (mode == CoinJoinMode.NONE || timeSkew > MAX_ALLOWED_TIMESKEW) {
if (mode == CoinJoinMode.NONE || !isInsideTimeSkewBounds(timeSkew)) {
updateMixingState(MixingStatus.NOT_STARTED)
} else {
configureMixing()
Expand Down
13 changes: 7 additions & 6 deletions wallet/src/de/schildbach/wallet/ui/main/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,15 @@ import org.dash.wallet.common.services.analytics.AnalyticsTimer
import org.dash.wallet.common.transactions.TransactionUtils.isEntirelySelf
import org.dash.wallet.common.transactions.TransactionWrapper
import org.dash.wallet.common.transactions.TransactionWrapperComparator
import org.dash.wallet.common.util.Constants.HTTP_CLIENT
import org.dash.wallet.common.util.head
import org.dash.wallet.common.util.toBigDecimal
import org.dash.wallet.integrations.crowdnode.transactions.FullCrowdNodeSignUpTxSet
import org.slf4j.LoggerFactory
import java.lang.Math.abs
import java.text.DecimalFormat
import java.util.Currency
import java.util.Locale
import javax.inject.Inject
import kotlin.collections.set
import kotlin.math.abs

@OptIn(ExperimentalCoroutinesApi::class, FlowPreview::class)
@HiltViewModel
Expand Down Expand Up @@ -138,7 +136,9 @@ class MainViewModel @Inject constructor(
private const val THROTTLE_DURATION = 500L
private const val DIRECTION_KEY = "tx_direction"
private const val TIME_SKEW_TOLERANCE = 3600000 // seconds (1 hour)
private const val TIME_SKEW_TOLERANCE_COINJOIN = 4000 // seconds
private const val TIME_SKEW_AHEAD_TOLERANCE_COINJOIN = 5000 // 5 seconds
private const val TIME_SKEW_BEHIND_TOLERANCE_COINJOIN = 20000 // 20 seconds

private val log = LoggerFactory.getLogger(MainViewModel::class.java)
}

Expand Down Expand Up @@ -392,10 +392,11 @@ class MainViewModel @Inject constructor(
val maxAllowedTimeSkew = if (coinJoinConfig.getMode() == CoinJoinMode.NONE) {
TIME_SKEW_TOLERANCE
} else {
TIME_SKEW_TOLERANCE_COINJOIN
if (timeSkew > 0) TIME_SKEW_AHEAD_TOLERANCE_COINJOIN else TIME_SKEW_BEHIND_TOLERANCE_COINJOIN
}
coinJoinService.updateTimeSkew(timeSkew)
return Pair(timeSkew > maxAllowedTimeSkew, timeSkew)
log.info("timeskew: {} ms", timeSkew)
return Pair(kotlin.math.abs(timeSkew) > maxAllowedTimeSkew, timeSkew)
} catch (ex: Exception) {
// Ignore errors
Pair(false, 0)
Expand Down
6 changes: 4 additions & 2 deletions wallet/src/de/schildbach/wallet/ui/main/WalletActivityExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import org.dash.wallet.common.services.analytics.AnalyticsConstants
import org.dash.wallet.common.ui.dialogs.AdaptiveDialog
import org.dash.wallet.common.ui.dialogs.AdaptiveDialog.Companion.create
import org.dash.wallet.common.util.openCustomTab
import kotlin.math.abs

object WalletActivityExt {
private const val STORAGE_TOLERANCE = 500 // MB
Expand Down Expand Up @@ -101,7 +102,7 @@ object WalletActivityExt {
if (isTimeSkewed && (!timeSkewDialogShown || coinJoinOn)) {
timeSkewDialogShown = true
// add 1 to round up so 2.2 seconds appears as 3
showTimeSkewAlertDialog(1 + timeSkew / 1000, coinJoinOn)
showTimeSkewAlertDialog((if (timeSkew > 0) 1 else -1) + timeSkew / 1000L, coinJoinOn)
}
}
}
Expand Down Expand Up @@ -179,7 +180,8 @@ object WalletActivityExt {
R.drawable.ic_warning,
getString(R.string.wallet_timeskew_dialog_title),
if (coinJoin) {
getString(R.string.wallet_coinjoin_timeskew_dialog_msg, diffSeconds)
val position = getString(if (diffSeconds > 0) R.string.timeskew_ahead else R.string.timeskew_behind)
getString(R.string.wallet_coinjoin_timeskew_dialog_msg, position, abs(diffSeconds))
} else {
getString(R.string.wallet_timeskew_dialog_msg, diffSeconds / 1000)
},
Expand Down
2 changes: 1 addition & 1 deletion wallet/src/de/schildbach/wallet/util/TimeUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,5 @@ suspend fun getTimeSkew(): Long {
requireNotNull(networkTime)
}
val systemTimeMillis = System.currentTimeMillis()
return abs(systemTimeMillis - networkTime)
return systemTimeMillis - networkTime
}

0 comments on commit 27bdd70

Please sign in to comment.