diff --git a/common/src/main/java/org/dash/wallet/common/data/entity/BlockchainState.kt b/common/src/main/java/org/dash/wallet/common/data/entity/BlockchainState.kt index f8f1dc97b3..16a3794d6d 100644 --- a/common/src/main/java/org/dash/wallet/common/data/entity/BlockchainState.kt +++ b/common/src/main/java/org/dash/wallet/common/data/entity/BlockchainState.kt @@ -25,7 +25,7 @@ import java.util.* data class BlockchainState(var bestChainDate: Date?, var bestChainHeight: Int, var replaying: Boolean, - var impediments: Set, + var impediments: MutableSet, var chainlockHeight: Int, var mnlistHeight: Int, var percentageSync: Int) { diff --git a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/api/CrowdNodeApi.kt b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/api/CrowdNodeApi.kt index 27a84c9fb9..d2990d0475 100644 --- a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/api/CrowdNodeApi.kt +++ b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/api/CrowdNodeApi.kt @@ -35,6 +35,7 @@ import org.dash.wallet.common.data.Resource import org.dash.wallet.common.data.ServiceName import org.dash.wallet.common.data.Status import org.dash.wallet.common.data.TaxCategory +import org.dash.wallet.common.services.BlockchainStateProvider import org.dash.wallet.common.services.LeftoverBalanceException import org.dash.wallet.common.services.NotificationService import org.dash.wallet.common.services.TransactionMetadataProvider @@ -94,6 +95,7 @@ class CrowdNodeApiAggregator @Inject constructor( private val config: CrowdNodeConfig, private val globalConfig: Configuration, private val transactionMetadataProvider: TransactionMetadataProvider, + private val blockchainStateProvider: BlockchainStateProvider, @ApplicationContext private val appContext: Context ) : CrowdNodeApi { companion object { @@ -299,6 +301,8 @@ class CrowdNodeApiAggregator @Inject constructor( if (result.messageStatus.lowercase() == MESSAGE_RECEIVED_STATUS) { log.info("Withdrawal request sent successfully") refreshBalance(retries = 3, afterWithdrawal = true) + val currentBlockHeight = blockchainStateProvider.getState()?.bestChainHeight ?: -1 + config.set(CrowdNodeConfig.LAST_WITHDRAWAL_BLOCK, currentBlockHeight) true } else { log.info("Withdrawal request not received, status: ${result.messageStatus}. Result: ${result.result}") @@ -331,6 +335,9 @@ class CrowdNodeApiAggregator @Inject constructor( config.get(CrowdNodeConfig.WITHDRAWAL_LIMIT_PER_DAY) ?: CrowdNodeConstants.WithdrawalLimits.DEFAULT_LIMIT_PER_DAY.value } + else -> { + 0L + } } ) } @@ -824,6 +831,11 @@ class CrowdNodeApiAggregator @Inject constructor( if (withdrawalsLast24h.add(value) > perDayLimit) { throw WithdrawalLimitsException(perDayLimit, WithdrawalLimitPeriod.PerDay) } + val lastWithdrawBlock = config.get(CrowdNodeConfig.LAST_WITHDRAWAL_BLOCK) + val currentBlockHeight = blockchainStateProvider.getState()?.bestChainHeight ?: -1 + if (lastWithdrawBlock != null && lastWithdrawBlock >= currentBlockHeight) { + throw WithdrawalLimitsException(value, WithdrawalLimitPeriod.PerBlock) + } } private fun refreshWithdrawalLimits() { diff --git a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/model/WithdrawalLimit.kt b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/model/WithdrawalLimit.kt index 6ca0241033..c769e601b2 100644 --- a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/model/WithdrawalLimit.kt +++ b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/model/WithdrawalLimit.kt @@ -30,7 +30,8 @@ data class WithdrawalLimit( enum class WithdrawalLimitPeriod { PerTransaction, PerHour, - PerDay + PerDay, + PerBlock } data class WithdrawalLimitsException( diff --git a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/dialogs/WithdrawalLimitsInfoDialog.kt b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/dialogs/WithdrawalLimitsInfoDialog.kt index 43a4afa688..eee4898e8e 100644 --- a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/dialogs/WithdrawalLimitsInfoDialog.kt +++ b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/dialogs/WithdrawalLimitsInfoDialog.kt @@ -30,6 +30,7 @@ import org.dash.wallet.common.ui.viewBinding import org.dash.wallet.integrations.crowdnode.R import org.dash.wallet.integrations.crowdnode.databinding.DialogWithdrawalLimitsBinding import org.dash.wallet.integrations.crowdnode.model.WithdrawalLimitPeriod +import java.lang.IllegalArgumentException class WithdrawalLimitsInfoDialog( private val limitPerTx: Coin, @@ -79,6 +80,9 @@ class WithdrawalLimitsInfoDialog( binding.perDayLimit.setTextColor(warningColor) TextViewCompat.setCompoundDrawableTintList(binding.perDayLimit, colorStateLit) } + else -> { + throw IllegalArgumentException("highlightedLimit $highlightedLimit not supported") + } } } diff --git a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/portal/TransferFragment.kt b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/portal/TransferFragment.kt index c50884fc33..0de83152a3 100644 --- a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/portal/TransferFragment.kt +++ b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/portal/TransferFragment.kt @@ -339,30 +339,39 @@ class TransferFragment : Fragment(R.layout.fragment_transfer) { } private suspend fun showWithdrawalLimitsError(period: WithdrawalLimitPeriod) { - val limits = viewModel.getWithdrawalLimits() - val okButtonText = if (period == WithdrawalLimitPeriod.PerTransaction) { - if (viewModel.onlineAccountStatus == OnlineAccountStatus.Done) { - getString(R.string.read_withdrawal_policy) + if (period == WithdrawalLimitPeriod.PerBlock) { + AdaptiveDialog.create( + R.drawable.ic_warning, + getString(R.string.crowdnode_withdrawal_limits_per_block_title), + getString(R.string.crowdnode_withdrawal_limits_per_block_message), + getString(R.string.button_okay) + ).showAsync(requireActivity()) + } else { + val limits = viewModel.getWithdrawalLimits() + val okButtonText = if (period == WithdrawalLimitPeriod.PerTransaction) { + if (viewModel.onlineAccountStatus == OnlineAccountStatus.Done) { + getString(R.string.read_withdrawal_policy) + } else { + getString(R.string.online_account_create) + } } else { - getString(R.string.online_account_create) + "" } - } else { - "" - } - val doAction = WithdrawalLimitsInfoDialog( - limits[0], - limits[1], - limits[2], - highlightedLimit = period, - okButtonText = okButtonText - ).showAsync(requireActivity()) - - if (doAction == true) { - if (viewModel.onlineAccountStatus == OnlineAccountStatus.Done) { - openWithdrawalPolicy() - } else { - safeNavigate(TransferFragmentDirections.transferToOnlineAccountEmail()) + val doAction = WithdrawalLimitsInfoDialog( + limits[0], + limits[1], + limits[2], + highlightedLimit = period, + okButtonText = okButtonText + ).showAsync(requireActivity()) + + if (doAction == true) { + if (viewModel.onlineAccountStatus == OnlineAccountStatus.Done) { + openWithdrawalPolicy() + } else { + safeNavigate(TransferFragmentDirections.transferToOnlineAccountEmail()) + } } } } diff --git a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/utils/CrowdNodeConfig.kt b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/utils/CrowdNodeConfig.kt index c31475aaf2..8cb8cabc5e 100644 --- a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/utils/CrowdNodeConfig.kt +++ b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/utils/CrowdNodeConfig.kt @@ -46,5 +46,6 @@ open class CrowdNodeConfig @Inject constructor( val WITHDRAWAL_LIMIT_PER_TX = longPreferencesKey("withdrawal_limit_per_tx") val WITHDRAWAL_LIMIT_PER_HOUR = longPreferencesKey("withdrawal_limit_per_hour") val WITHDRAWAL_LIMIT_PER_DAY = longPreferencesKey("withdrawal_limit_per_day") + val LAST_WITHDRAWAL_BLOCK = intPreferencesKey("last_withdrawal_block") } } diff --git a/integrations/crowdnode/src/main/res/values/strings-crowdnode.xml b/integrations/crowdnode/src/main/res/values/strings-crowdnode.xml index d4464a1098..09a8b869ed 100644 --- a/integrations/crowdnode/src/main/res/values/strings-crowdnode.xml +++ b/integrations/crowdnode/src/main/res/values/strings-crowdnode.xml @@ -143,6 +143,8 @@ Due to CrowdNode’s terms of service users can withdraw no more than: Withdraw without limits with an online account on CrowdNode website. This error is most likely due to exceeding CrowdNode withdrawal limits. Try again later. + Please wait before initiating the next withdrawal + Please wait 5 minutes before initiating another withdrawal. per transaction per hour per 24 hours diff --git a/integrations/crowdnode/src/test/java/org/dash/wallet/integrations/crowdnode/CrowdNodeApiAggregatorTest.kt b/integrations/crowdnode/src/test/java/org/dash/wallet/integrations/crowdnode/CrowdNodeApiAggregatorTest.kt index 7421e42c08..eb029ae18f 100644 --- a/integrations/crowdnode/src/test/java/org/dash/wallet/integrations/crowdnode/CrowdNodeApiAggregatorTest.kt +++ b/integrations/crowdnode/src/test/java/org/dash/wallet/integrations/crowdnode/CrowdNodeApiAggregatorTest.kt @@ -93,7 +93,7 @@ class CrowdNodeApiAggregatorTest { localConfig.stub { onBlocking { get(CrowdNodeConfig.ONLINE_ACCOUNT_STATUS) } doReturn OnlineAccountStatus.Linking.ordinal } - val api = CrowdNodeApiAggregator(webApi, blockchainApi, walletData, mock(), mock(), localConfig, globalConfig, mock(), mock()) // ktlint-disable max-line-length + val api = CrowdNodeApiAggregator(webApi, blockchainApi, walletData, mock(), mock(), localConfig, globalConfig, mock(), mock(), mock()) // ktlint-disable max-line-length api.restoreStatus() api.stopTrackingLinked() @@ -112,7 +112,7 @@ class CrowdNodeApiAggregatorTest { } val api = CrowdNodeApiAggregator( mock(), blockchainApi, walletData, mock(), mock(), - localConfig, globalConfig, mock(), mock() + localConfig, globalConfig, mock(), mock(), mock() ) api.restoreStatus() api.stopTrackingLinked() @@ -139,7 +139,7 @@ class CrowdNodeApiAggregatorTest { blockchainApi.stub { on { getFullSignUpTxSet() } doReturn mockFullSet } - val api = CrowdNodeApiAggregator(webApi, blockchainApi, walletData, mock(), mock(), localConfig, globalConfig, mock(), mock()) // ktlint-disable max-line-length + val api = CrowdNodeApiAggregator(webApi, blockchainApi, walletData, mock(), mock(), localConfig, globalConfig, mock(), mock(), mock()) // ktlint-disable max-line-length api.restoreStatus() assertEquals(SignUpStatus.Finished, api.signUpStatus.value) assertEquals(OnlineAccountStatus.None, api.onlineAccountStatus.value) @@ -159,7 +159,7 @@ class CrowdNodeApiAggregatorTest { } val api = CrowdNodeApiAggregator( webApi, blockchainApi, walletData, mock(), mock(), - localConfig, globalConfig, mock(), mock() + localConfig, globalConfig, mock(), mock(), mock() ) api.restoreStatus() api.refreshBalance() @@ -177,7 +177,7 @@ class CrowdNodeApiAggregatorTest { } val api = CrowdNodeApiAggregator( webApi, blockchainApi, walletData, mock(), mock(), - localConfig, globalConfig, mock(), mock() + localConfig, globalConfig, mock(), mock(), mock() ) api.restoreStatus() assertEquals(SignUpStatus.LinkedOnline, api.signUpStatus.value) @@ -204,7 +204,7 @@ class CrowdNodeApiAggregatorTest { } val api = CrowdNodeApiAggregator( webApi, blockchainApi, walletData, mock(), mock(), - localConfig, globalConfig, mock(), mock() + localConfig, globalConfig, mock(), mock(), mock() ) api.restoreStatus() assertEquals(SignUpStatus.Finished, api.signUpStatus.value) @@ -238,7 +238,7 @@ class CrowdNodeApiAggregatorTest { val api = CrowdNodeApiAggregator( webApi, blockchainApi, walletData, mock(), mock(), - localConfig, globalConfig, mock(), mock() + localConfig, globalConfig, mock(), mock(), mock() ) api.restoreStatus() diff --git a/wallet/src/de/schildbach/wallet/WalletApplication.java b/wallet/src/de/schildbach/wallet/WalletApplication.java index 0cfe198f1f..baf255e3cc 100644 --- a/wallet/src/de/schildbach/wallet/WalletApplication.java +++ b/wallet/src/de/schildbach/wallet/WalletApplication.java @@ -30,7 +30,6 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.database.sqlite.SQLiteException; import android.media.AudioAttributes; import android.net.Uri; import android.os.Build; @@ -52,9 +51,6 @@ import androidx.work.WorkManager; import com.google.common.base.Stopwatch; -import com.google.common.hash.HashCode; -import com.google.common.hash.Hasher; -import com.google.common.hash.Hashing; import org.bitcoinj.core.Address; import org.bitcoinj.core.Coin; @@ -70,7 +66,6 @@ import org.bitcoinj.wallet.Protos; import org.bitcoinj.wallet.UnreadableWalletException; import org.bitcoinj.wallet.Wallet; -import org.bitcoinj.wallet.WalletExtension; import org.bitcoinj.wallet.WalletProtobufSerializer; import org.bitcoinj.wallet.authentication.AuthenticationGroupExtension; import org.bitcoinj.wallet.authentication.AuthenticationKeyUsage; @@ -86,6 +81,7 @@ import org.dash.wallet.features.exploredash.utils.DashDirectConstants; import org.dash.wallet.integrations.coinbase.service.CoinBaseClientConstants; +import de.schildbach.wallet.service.BlockchainStateDataProvider; import de.schildbach.wallet.service.PackageInfoProvider; import de.schildbach.wallet.service.WalletFactory; import de.schildbach.wallet.transactions.MasternodeObserver; @@ -123,8 +119,6 @@ import ch.qos.logback.core.rolling.RollingFileAppender; import ch.qos.logback.core.rolling.TimeBasedRollingPolicy; import dagger.hilt.android.HiltAndroidApp; -import org.dash.wallet.common.data.entity.BlockchainState; -import de.schildbach.wallet.database.dao.BlockchainStateDao; import de.schildbach.wallet.service.BlockchainService; import de.schildbach.wallet.service.BlockchainServiceImpl; import de.schildbach.wallet.service.BlockchainSyncJobService; @@ -186,7 +180,7 @@ public class WalletApplication extends MultiDexApplication @Inject HiltWorkerFactory workerFactory; @Inject - BlockchainStateDao blockchainStateDao; + BlockchainStateDataProvider blockchainStateDataProvider; @Inject CrowdNodeConfig crowdNodeConfig; @Inject @@ -749,9 +743,7 @@ public void stopBlockchainService() { } public void resetBlockchainState() { - Executors.newSingleThreadExecutor().execute(() -> { - blockchainStateDao.save(new BlockchainState(true)); - }); + blockchainStateDataProvider.resetBlockchainState(); } public void resetBlockchain() { @@ -768,20 +760,7 @@ public void resetBlockchain() { } private void resetBlockchainSyncProgress() { - Executors.newSingleThreadExecutor().execute(() -> { - BlockchainState blockchainState; - - try { - blockchainState = blockchainStateDao.loadSync(); - } catch (SQLiteException ex) { - blockchainState = null; - } - - if (blockchainState != null) { - blockchainState.setPercentageSync(0); - blockchainStateDao.save(blockchainState); - } - }); + blockchainStateDataProvider.resetBlockchainSyncProgress(); } public void replaceWallet(final Wallet newWallet) { diff --git a/wallet/src/de/schildbach/wallet/database/dao/BlockchainStateDao.kt b/wallet/src/de/schildbach/wallet/database/dao/BlockchainStateDao.kt index 1e588d45fa..c447f88a7a 100644 --- a/wallet/src/de/schildbach/wallet/database/dao/BlockchainStateDao.kt +++ b/wallet/src/de/schildbach/wallet/database/dao/BlockchainStateDao.kt @@ -17,7 +17,6 @@ package de.schildbach.wallet.database.dao -import androidx.lifecycle.LiveData import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy @@ -32,9 +31,9 @@ import org.dash.wallet.common.data.entity.BlockchainState abstract class BlockchainStateDao { @Insert(onConflict = OnConflictStrategy.REPLACE) - protected abstract fun insert(blockchainState: BlockchainState) + protected abstract suspend fun insert(blockchainState: BlockchainState) - fun save(blockchainState: BlockchainState) { + suspend fun saveState(blockchainState: BlockchainState) { if (blockchainState.replaying && blockchainState.percentageSync == 100) { blockchainState.replaying = false } @@ -42,13 +41,7 @@ abstract class BlockchainStateDao { } @Query("SELECT * FROM blockchain_state LIMIT 1") - abstract fun load(): LiveData - - @Query("SELECT * FROM blockchain_state LIMIT 1") - abstract fun loadSync(): BlockchainState? - - @Query("SELECT * FROM blockchain_state LIMIT 1") - abstract suspend fun get(): BlockchainState? + abstract suspend fun getState(): BlockchainState? @Query("SELECT * FROM blockchain_state LIMIT 1") abstract fun observeState(): Flow diff --git a/wallet/src/de/schildbach/wallet/service/BlockchainServiceImpl.java b/wallet/src/de/schildbach/wallet/service/BlockchainServiceImpl.java index f6a43720f5..722da2ed39 100644 --- a/wallet/src/de/schildbach/wallet/service/BlockchainServiceImpl.java +++ b/wallet/src/de/schildbach/wallet/service/BlockchainServiceImpl.java @@ -87,6 +87,7 @@ import org.dash.wallet.common.transactions.filters.TransactionFilter; import org.dash.wallet.common.services.TransactionMetadataProvider; import org.dash.wallet.common.transactions.TransactionUtils; +import org.dash.wallet.common.util.FlowExtKt; import org.dash.wallet.integrations.crowdnode.api.CrowdNodeAPIConfirmationHandler; import org.dash.wallet.integrations.crowdnode.api.CrowdNodeBlockchainApi; import org.dash.wallet.integrations.crowdnode.transactions.CrowdNodeDepositReceivedResponse; @@ -132,6 +133,9 @@ import de.schildbach.wallet.util.CrashReporter; import de.schildbach.wallet.util.ThrottlingWalletChangeListener; import de.schildbach.wallet_test.R; +import kotlin.Unit; +import kotlin.coroutines.Continuation; +import kotlinx.coroutines.flow.FlowCollector; import static org.dash.wallet.common.util.Constants.PREFIX_ALMOST_EQUAL_TO; @@ -148,6 +152,7 @@ public class BlockchainServiceImpl extends LifecycleService implements Blockchai @Inject CrowdNodeBlockchainApi crowdNodeBlockchainApi; @Inject CrowdNodeConfig crowdNodeConfig; @Inject BlockchainStateDao blockchainStateDao; + @Inject BlockchainStateDataProvider blockchainStateDataProvider; @Inject ExchangeRatesDao exchangeRatesDao; @Inject TransactionMetadataProvider transactionMetadataProvider; @Inject PackageInfoProvider packageInfoProvider; @@ -976,7 +981,10 @@ public void onCreate() { peerDiscoveryList.add(dnsDiscovery); updateAppWidget(); - blockchainStateDao.load().observe(this, this::handleBlockchainStateNotification); + FlowExtKt.observe(blockchainStateDao.observeState(), this, (blockchainState, continuation) -> { + handleBlockchainStateNotification((BlockchainState) blockchainState); + return null; + }); registerCrowdNodeConfirmedAddressFilter(); } @@ -1154,47 +1162,15 @@ private Notification createNetworkSyncNotification(BlockchainState blockchainSta } private void updateBlockchainStateImpediments() { - executor.execute(() -> { - BlockchainState blockchainState = blockchainStateDao.loadSync(); - if (blockchainState != null) { - blockchainState.getImpediments().clear(); - blockchainState.getImpediments().addAll(impediments); - blockchainStateDao.save(blockchainState); - } - }); + blockchainStateDataProvider.updateImpediments(impediments); } private void updateBlockchainState() { - executor.execute(() -> { - BlockchainState blockchainState = blockchainStateDao.loadSync(); - if (blockchainState == null) { - blockchainState = new BlockchainState(); - } - - StoredBlock chainHead = blockChain.getChainHead(); - StoredBlock block = application.getWallet().getContext().chainLockHandler.getBestChainLockBlock(); - int chainLockHeight = block != null ? block.getHeight() : 0; - int mnListHeight = (int) application.getWallet().getContext().masternodeListManager.getListAtChainTip().getHeight(); - - blockchainState.setBestChainDate(chainHead.getHeader().getTime()); - blockchainState.setBestChainHeight(chainHead.getHeight()); - blockchainState.setImpediments(EnumSet.copyOf(impediments)); - blockchainState.setChainlockHeight(chainLockHeight); - blockchainState.setMnlistHeight(mnListHeight); - blockchainState.setPercentageSync(percentageSync()); - - blockchainStateDao.save(blockchainState); - }); + blockchainStateDataProvider.updateBlockchainState(blockChain, impediments, percentageSync()); } public void setBlockchainDownloaded() { - executor.execute(() -> { - BlockchainState blockchainState = blockchainStateDao.loadSync(); - if (blockchainState != null && blockchainState.getPercentageSync() != 100) { - blockchainState.setPercentageSync(100); - blockchainStateDao.save(blockchainState); - } - }); + blockchainStateDataProvider.setBlockchainDownloaded(); } @Override diff --git a/wallet/src/de/schildbach/wallet/service/BlockchainStateDataProvider.kt b/wallet/src/de/schildbach/wallet/service/BlockchainStateDataProvider.kt index 4d45daf1c1..02015ed411 100644 --- a/wallet/src/de/schildbach/wallet/service/BlockchainStateDataProvider.kt +++ b/wallet/src/de/schildbach/wallet/service/BlockchainStateDataProvider.kt @@ -18,12 +18,17 @@ package de.schildbach.wallet.service import android.content.Context +import android.database.sqlite.SQLiteException import dagger.hilt.android.qualifiers.ApplicationContext import de.schildbach.wallet.Constants import de.schildbach.wallet.database.dao.BlockchainStateDao +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.launch import org.bitcoinj.core.Block +import org.bitcoinj.core.BlockChain import org.bitcoinj.core.CheckpointManager import org.bitcoinj.core.Coin import org.bitcoinj.core.NetworkParameters @@ -32,10 +37,12 @@ import org.bitcoinj.store.BlockStoreException import org.dash.wallet.common.Configuration import org.dash.wallet.common.WalletDataProvider import org.dash.wallet.common.data.entity.BlockchainState +import org.dash.wallet.common.data.entity.BlockchainState.Impediment import org.dash.wallet.common.services.BlockchainStateProvider import java.io.IOException import java.io.InputStream import java.math.BigInteger +import java.util.EnumSet import javax.inject.Inject import kotlin.math.min @@ -67,14 +74,79 @@ class BlockchainStateDataProvider @Inject constructor( const val MASTERNODE_COUNT = 3800 } + private val coroutineScope = CoroutineScope(Dispatchers.IO) + override suspend fun getState(): BlockchainState? { - return blockchainStateDao.loadSync() + return blockchainStateDao.getState() } override fun observeState(): Flow { return blockchainStateDao.observeState().distinctUntilChanged() } + fun updateImpediments(impediments: Set) { + coroutineScope.launch { + val blockchainState = blockchainStateDao.getState() + if (blockchainState != null) { + blockchainState.impediments.clear() + blockchainState.impediments.addAll(impediments) + blockchainStateDao.saveState(blockchainState) + } + } + } + + fun updateBlockchainState(blockChain: BlockChain, impediments: Set, percentageSync: Int) { + coroutineScope.launch { + var blockchainState = blockchainStateDao.getState() + if (blockchainState == null) { + blockchainState = BlockchainState() + } + val chainHead: StoredBlock = blockChain.chainHead + val chainLockHeight = walletDataProvider.wallet!!.context.chainLockHandler.bestChainLockBlockHeight + val mnListHeight: Int = + walletDataProvider.wallet!!.context.masternodeListManager.listAtChainTip.height.toInt() + blockchainState.bestChainDate = chainHead.header.time + blockchainState.bestChainHeight = chainHead.height + blockchainState.impediments = EnumSet.copyOf(impediments) + blockchainState.chainlockHeight = chainLockHeight + blockchainState.mnlistHeight = mnListHeight + blockchainState.percentageSync = percentageSync + blockchainStateDao.saveState(blockchainState) + } + } + + fun setBlockchainDownloaded() { + coroutineScope.launch { + val blockchainState = blockchainStateDao.getState() + if (blockchainState != null && blockchainState.percentageSync != 100) { + blockchainState.percentageSync = 100 + blockchainStateDao.saveState(blockchainState) + } + } + } + + fun resetBlockchainState() { + coroutineScope.launch { + blockchainStateDao.saveState( + BlockchainState(true) + ) + } + } + + fun resetBlockchainSyncProgress() { + coroutineScope.launch { + val blockchainState: BlockchainState? = try { + blockchainStateDao.getState() + } catch (ex: SQLiteException) { + null + } + if (blockchainState != null) { + blockchainState.percentageSync = 0 + blockchainStateDao.saveState(blockchainState) + } + } + } + override fun getLastMasternodeAPY(): Double { val apy = configuration.prefsKeyCrowdNodeStakingApy.toDouble() return if (apy != 0.0) { diff --git a/wallet/src/de/schildbach/wallet/ui/more/ToolsFragment.kt b/wallet/src/de/schildbach/wallet/ui/more/ToolsFragment.kt index 332c3818fa..d86842f0e3 100644 --- a/wallet/src/de/schildbach/wallet/ui/more/ToolsFragment.kt +++ b/wallet/src/de/schildbach/wallet/ui/more/ToolsFragment.kt @@ -46,6 +46,7 @@ import org.dash.wallet.common.ui.BaseAlertDialogBuilder import org.dash.wallet.common.ui.dialogs.AdaptiveDialog import org.dash.wallet.common.ui.viewBinding import org.dash.wallet.common.util.Qr +import org.dash.wallet.common.util.observe import org.slf4j.LoggerFactory import javax.inject.Inject diff --git a/wallet/src/de/schildbach/wallet/ui/more/ToolsViewModel.kt b/wallet/src/de/schildbach/wallet/ui/more/ToolsViewModel.kt index c0a2aa99f2..578fa05275 100644 --- a/wallet/src/de/schildbach/wallet/ui/more/ToolsViewModel.kt +++ b/wallet/src/de/schildbach/wallet/ui/more/ToolsViewModel.kt @@ -42,7 +42,7 @@ class ToolsViewModel @Inject constructor( val blockchainStateDao: BlockchainStateDao, ) : ViewModel() { - val blockchainState = blockchainStateDao.load() + val blockchainState = blockchainStateDao.observeState() val xpub: String val xpubWithCreationDate: String