Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: fix username creation bugs and remove some ANR's #1350

Merged
merged 17 commits into from
Feb 25, 2025
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ buildscript {
coroutinesVersion = '1.6.4'
ok_http_version = '4.9.1'
dashjVersion = '21.1.6'
dppVersion = "1.7.2"
dppVersion = "1.7.3-SNAPSHOT"
hiltVersion = '2.51'
hiltCompilerVersion = '1.2.0'
hiltWorkVersion = '1.0.0'
Expand Down
30 changes: 21 additions & 9 deletions wallet/src/de/schildbach/wallet/service/BlockchainServiceImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,6 @@ class BlockchainServiceImpl : LifecycleService(), BlockchainService {
private var peerGroup: PeerGroup? = null
private val handler = Handler()
private val delayHandler = Handler()
private val metadataHandler = Handler()
private var wakeLock: PowerManager.WakeLock? = null
private var peerConnectivityListener: PeerConnectivityListener? = null
private var nm: NotificationManager? = null
Expand All @@ -241,6 +240,8 @@ class BlockchainServiceImpl : LifecycleService(), BlockchainService {
private var syncPercentage = 0 // 0 to 100%
private var mixingStatus = MixingStatus.NOT_STARTED
private var mixingProgress = 0.0
private var balance = Coin.ZERO
private var mixedBalance = Coin.ZERO
private var foregroundService = ForegroundService.NONE

// Risk Analyser for Transactions that is PeerGroup Aware
Expand All @@ -254,10 +255,8 @@ class BlockchainServiceImpl : LifecycleService(), BlockchainService {
CrowdNodeDepositReceivedResponse(Constants.NETWORK_PARAMETERS)
private var apiConfirmationHandler: CrowdNodeAPIConfirmationHandler? = null
private fun handleMetadata(tx: Transaction) {
metadataHandler.post {
transactionMetadataProvider.syncTransactionBlocking(
tx
)
serviceScope.launch {
transactionMetadataProvider.syncTransaction(tx)
Comment on lines -257 to +261
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use coroutine instead of a Handler()

}
}

Expand Down Expand Up @@ -708,7 +707,7 @@ class BlockchainServiceImpl : LifecycleService(), BlockchainService {
packageInfoProvider.packageInfo
)
}
org.bitcoinj.core.Context.propagate(wallet.context)
propagateContext()
dashSystemService.system.initDashSync(getDir("masternode", MODE_PRIVATE).absolutePath)
log.info("starting peergroup")
peerGroup = PeerGroup(Constants.NETWORK_PARAMETERS, blockChain, headerChain)
Expand Down Expand Up @@ -1012,6 +1011,9 @@ class BlockchainServiceImpl : LifecycleService(), BlockchainService {
}

private fun propagateContext() {
if (application.wallet?.context != Constants.CONTEXT) {
log.warn("wallet context does not equal Constants.CONTEXT")
}
org.bitcoinj.core.Context.propagate(Constants.CONTEXT)
}

Expand Down Expand Up @@ -1125,14 +1127,23 @@ class BlockchainServiceImpl : LifecycleService(), BlockchainService {
coinJoinService.observeMixingProgress().observe(this@BlockchainServiceImpl) { mixingProgress ->
handleBlockchainStateNotification(blockchainState, mixingStatus, mixingProgress)
}

application.observeBalance().observe(this@BlockchainServiceImpl) {
balance = it
handleBlockchainStateNotification(blockchainState, mixingStatus, mixingProgress)
}

application.observeBalance(Wallet.BalanceType.COINJOIN_SPENDABLE).observe(this@BlockchainServiceImpl) {
mixedBalance = it
handleBlockchainStateNotification(blockchainState, mixingStatus, mixingProgress)
}

onCreateCompleted.complete(Unit) // Signal completion of onCreate
log.info(".onCreate() finished")
}
}

private fun createCoinJoinNotification(): Notification {
val mixedBalance = (application.wallet as WalletEx?)!!.coinJoinBalance
val totalBalance = application.wallet!!.balance
val notificationIntent = createIntent(this)
val pendingIntent = PendingIntent.getActivity(
this, 0,
Expand All @@ -1150,7 +1161,7 @@ class BlockchainServiceImpl : LifecycleService(), BlockchainService {
getString(statusStringId),
mixingProgress,
decimalFormat.format(mixedBalance.toBigDecimal()),
decimalFormat.format(totalBalance.toBigDecimal())
decimalFormat.format(balance.toBigDecimal())
)
return NotificationCompat.Builder(
this,
Expand Down Expand Up @@ -1330,6 +1341,7 @@ class BlockchainServiceImpl : LifecycleService(), BlockchainService {
throw RuntimeException(x)
}
if (!deleteWalletFileOnShutdown) {
propagateContext()
application.saveWallet()
}
if (wakeLock!!.isHeld) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,35 @@ package de.schildbach.wallet.transactions

import de.schildbach.wallet.Constants
import de.schildbach.wallet.util.ThrottlingWalletChangeListener
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.launch
import org.bitcoinj.core.Coin
import org.bitcoinj.core.Transaction
import org.bitcoinj.utils.Threading
import org.bitcoinj.wallet.Wallet

class WalletMostRecentTransactionsObserver(private val wallet: Wallet) {
private val workerJob = SupervisorJob()
private val workerScope = CoroutineScope(Dispatchers.IO + workerJob)
fun observe(): Flow<Transaction> = callbackFlow {
fun emitMostRecentTransaction() {
org.bitcoinj.core.Context.propagate(Constants.CONTEXT)
val allTxs = wallet.walletTransactions
if (allTxs.any()) {
var mostRecentTx = allTxs.first()
allTxs.forEach {
if (it.transaction.updateTime > mostRecentTx.transaction.updateTime) {
mostRecentTx = it
workerScope.launch {
org.bitcoinj.core.Context.propagate(Constants.CONTEXT)
val allTxs = wallet.walletTransactions
if (allTxs.any()) {
var mostRecentTx = allTxs.first()
allTxs.forEach {
if (it.transaction.updateTime > mostRecentTx.transaction.updateTime) {
mostRecentTx = it
}
}
trySend(mostRecentTx.transaction)
Comment on lines +39 to +49
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid an ANR when starting the app

}
trySend(mostRecentTx.transaction)
}
}

Expand Down Expand Up @@ -84,6 +92,7 @@ class WalletMostRecentTransactionsObserver(private val wallet: Wallet) {
wallet.removeCoinsSentEventListener(walletChangeListener)
wallet.removeCoinsReceivedEventListener(walletChangeListener)
walletChangeListener.removeCallbacks()
workerJob.cancel()
}
}
}
9 changes: 6 additions & 3 deletions wallet/src/de/schildbach/wallet/ui/LockScreenActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import de.schildbach.wallet.ui.verify.VerifySeedActivity
import de.schildbach.wallet.ui.widget.PinPreviewView
import de.schildbach.wallet_test.R
import de.schildbach.wallet_test.databinding.ActivityLockScreenRootBinding
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import org.bitcoinj.wallet.Wallet.BalanceType
import org.dash.wallet.common.Configuration
Expand Down Expand Up @@ -173,9 +174,11 @@ open class LockScreenActivity : SecureActivity() {
}

private fun setupBackupSeedReminder() {
val hasBalance = walletData.wallet?.getBalance(BalanceType.ESTIMATED)?.isPositive ?: false
if (hasBalance && configuration.lastBackupSeedTime == 0L) {
configuration.setLastBackupSeedTime()
lifecycleScope.launch {
val hasBalance = walletApplication.observeBalance().first().isPositive
if (hasBalance && configuration.lastBackupSeedTime == 0L) {
configuration.setLastBackupSeedTime()
}
}
}

Expand Down
43 changes: 24 additions & 19 deletions wallet/src/de/schildbach/wallet/ui/dashpay/CreateIdentityService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import dagger.hilt.android.AndroidEntryPoint
import de.schildbach.wallet.Constants
import de.schildbach.wallet.WalletApplication
import de.schildbach.wallet.data.CoinJoinConfig
import de.schildbach.wallet.data.CreditBalanceInfo
import de.schildbach.wallet.data.InvitationLinkData
import de.schildbach.wallet.database.dao.UserAlertDao
import de.schildbach.wallet.database.dao.UsernameRequestDao
Expand Down Expand Up @@ -318,10 +319,12 @@ class CreateIdentityService : LifecycleService() {
}

if (blockchainIdentityData.creationState == CreationState.USERNAME_REGISTERING) {
if (blockchainIdentityData.creationStateErrorMessage?.contains("preorderDocument was not found with a salted domain hash") == true) {
val errorMessage = blockchainIdentityData.creationStateErrorMessage ?: ""
if (errorMessage.contains("preorderDocument was not found with a salted domain hash") ||
errorMessage.contains("cannot find preorder document, though it should be somewhere")) {
blockchainIdentityData.creationState = CreationState.PREORDER_REGISTERING
platformRepo.updateBlockchainIdentityData(blockchainIdentityData)
} else if (blockchainIdentityData.creationStateErrorMessage?.contains("missing domain document for") == true) {
} else if (errorMessage.contains("missing domain document for")) {
blockchainIdentityData.creationState = CreationState.PREORDER_REGISTERING
platformRepo.updateBlockchainIdentityData(blockchainIdentityData)
} else if (retryWithNewUserName) {
Expand Down Expand Up @@ -374,26 +377,28 @@ class CreateIdentityService : LifecycleService() {
assetLockTransaction = blockchainIdentity.assetLockTransaction
}
} else {
val balanceInfo = platformRepo.getIdentityBalance()
val balanceRequirement = if (Names.isUsernameContestable(blockchainIdentityData.username!!)) {
Constants.DASH_PAY_FEE_CONTESTED
// don't use platformRepo.getIdentityBalance() because platformRepo.blockchainIdentity is not initialized
val balanceInfo = blockchainIdentityData.identity?.let { platformRepo.getIdentityBalance(it.id) }
?: CreditBalanceInfo(0L)
val balanceRequirement = if (Names.isUsernameContestable(blockchainIdentityData.username!!)) {
Constants.DASH_PAY_FEE_CONTESTED
} else {
Constants.DASH_PAY_FEE
}

if (balanceInfo.balance < balanceRequirement.value * 1000) {
val topupValue = if (Names.isUsernameContestable(blockchainIdentityData.username!!)) {
Constants.DASH_PAY_FEE_CONTESTED_NAME
} else {
Constants.DASH_PAY_FEE
}

if (balanceInfo.balance < balanceRequirement.value * 1000) {
val topupValue = if (Names.isUsernameContestable(blockchainIdentityData.username!!)) {
Constants.DASH_PAY_FEE_CONTESTED_NAME
} else {
Constants.DASH_PAY_FEE
}
assetLockTransaction = topUpRepository.createTopupTransaction(
blockchainIdentity,
topupValue,
encryptionKey,
useCoinJoin
)
}
assetLockTransaction = topUpRepository.createTopupTransaction(
blockchainIdentity,
topupValue,
encryptionKey,
useCoinJoin
)
}
}
}

Expand Down
16 changes: 12 additions & 4 deletions wallet/src/de/schildbach/wallet/ui/main/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ import org.dash.wallet.common.util.toBigDecimal
import org.dash.wallet.integrations.crowdnode.api.CrowdNodeApi
import org.dash.wallet.integrations.crowdnode.transactions.FullCrowdNodeSignUpTxSetFactory
import org.slf4j.LoggerFactory
import java.math.BigDecimal
import java.text.DecimalFormat
import java.time.Instant
import java.time.LocalDate
Expand Down Expand Up @@ -205,6 +206,9 @@ class MainViewModel @Inject constructor(
private val _balance = MutableLiveData<Coin>()
val balance: LiveData<Coin>
get() = _balance
private val _mixedBalance = MutableLiveData<Coin>()
val mixedBalance: LiveData<Coin>
get() = _mixedBalance

private var txByHash: Map<String, TransactionRowView> = mapOf()
private var metadata: Map<Sha256Hash, PresentableTxMetadata> = mapOf()
Expand Down Expand Up @@ -249,11 +253,11 @@ class MainViewModel @Inject constructor(
get() = coinJoinService.observeActiveSessions()

var decimalFormat: DecimalFormat = DecimalFormat("0.000")
val walletBalance: String
get() = decimalFormat.format(walletData.wallet!!.getBalance(Wallet.BalanceType.ESTIMATED).toBigDecimal())
val walletBalanceString: String
get() = decimalFormat.format(balance.value?.toBigDecimal() ?: BigDecimal.ZERO)

val mixedBalance: String
get() = decimalFormat.format((walletData.wallet as WalletEx).coinJoinBalance.toBigDecimal())
val mixedBalanceString: String
get() = decimalFormat.format(mixedBalance.value?.toBigDecimal() ?: BigDecimal.ZERO)

// DashPay
private val isPlatformAvailable = MutableStateFlow(false)
Expand Down Expand Up @@ -351,6 +355,10 @@ class MainViewModel @Inject constructor(
.onEach(_balance::postValue)
.launchIn(viewModelScope)

walletData.observeBalance(Wallet.BalanceType.COINJOIN_SPENDABLE)
.onEach(_mixedBalance::postValue)
.launchIn(viewModelScope)

walletData.observeMostRecentTransaction()
.onEach(_mostRecentTransaction::postValue)
.launchIn(viewModelScope)
Expand Down
24 changes: 14 additions & 10 deletions wallet/src/de/schildbach/wallet/ui/main/WalletFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -172,11 +172,7 @@ class WalletFragment : Fragment(R.layout.home_content) {
}

viewModel.mixingProgress.observe(viewLifecycleOwner) { progress ->
mixingBinding.balance.text = getString(
R.string.coinjoin_progress_balance,
viewModel.mixedBalance,
viewModel.walletBalance
)
updateMixedAndTotalBalance()
mixingBinding.mixingPercent.text = getString(R.string.percent, progress.toInt())
mixingBinding.mixingProgress.progress = progress.toInt()
}
Expand Down Expand Up @@ -210,18 +206,26 @@ class WalletFragment : Fragment(R.layout.home_content) {
}

viewModel.balance.observe(viewLifecycleOwner) {
mixingBinding.balance.text = getString(
R.string.coinjoin_progress_balance,
viewModel.mixedBalance,
viewModel.walletBalance
)
updateMixedAndTotalBalance()
}

viewModel.mixedBalance.observe(viewLifecycleOwner) {
updateMixedAndTotalBalance()
}

viewModel.hasContacts.observe(viewLifecycleOwner) {
refreshShortcutBar()
}
}

private fun updateMixedAndTotalBalance() {
mixingBinding.balance.text = getString(
R.string.coinjoin_progress_balance,
viewModel.mixedBalanceString,
viewModel.walletBalanceString
)
}

fun scrollToTop() {
if (!isAdded) {
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ class TransactionGroupViewModel @Inject constructor(
TransactionRowView.fromTransaction(
it, walletData.wallet!!, walletData.wallet!!.context, txMetadata, null, resourceMapper, chainLockBlockHeight
)
}
}.sortedBy { row -> row.time }
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sort TX in a group by date.

_dashValue.value = transactionWrapper.getValue(walletData.transactionBag)
}
}
Loading