Skip to content

Commit 197ad8f

Browse files
committed
Override local unspent outputs when remote index conflicts
1 parent f97087a commit 197ad8f

File tree

1 file changed

+29
-0
lines changed

1 file changed

+29
-0
lines changed

app/src/main/java/one/mixin/android/db/web3/WalletOutputDao.kt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package one.mixin.android.db.web3
22

33
import androidx.room.Dao
4+
import androidx.room.ColumnInfo
45
import androidx.room.Query
56
import androidx.room.Transaction
67
import one.mixin.android.api.response.web3.WalletOutput
@@ -39,8 +40,27 @@ interface WalletOutputDao: BaseDao<WalletOutput> {
3940
@Query("UPDATE outputs SET status = 'signed' WHERE output_id IN (:outputIds)")
4041
suspend fun updateOutputsToSigned(outputIds: List<String>): Int
4142

43+
@Query("SELECT output_id, transaction_hash, output_index FROM outputs WHERE address = :address AND asset_id = :assetId AND status = 'unspent' AND output_index IN (:outputIndexes)")
44+
suspend fun findLocalUnspentOutputsByIndexes(address: String, assetId: String, outputIndexes: List<Long>): List<LocalUnspentOutputIndex>
45+
4246
@Transaction
4347
suspend fun mergeOutputsForAddress(address: String, assetId: String, remoteOutputs: List<WalletOutput>) {
48+
val remoteOutputIndexes: List<Long> = remoteOutputs.map { it.outputIndex }.distinct()
49+
if (remoteOutputIndexes.isNotEmpty()) {
50+
val remoteTxHashesByIndex: Map<Long, Set<String>> = remoteOutputs
51+
.groupBy { it.outputIndex }
52+
.mapValues { entry -> entry.value.map { it.transactionHash }.toSet() }
53+
val localUnspentByIndex: List<LocalUnspentOutputIndex> = findLocalUnspentOutputsByIndexes(address, assetId, remoteOutputIndexes)
54+
val conflictOutputIds: List<String> = localUnspentByIndex
55+
.filter { local ->
56+
val remoteTxHashes: Set<String> = remoteTxHashesByIndex[local.outputIndex] ?: emptySet()
57+
!remoteTxHashes.contains(local.transactionHash)
58+
}
59+
.map { it.outputId }
60+
if (conflictOutputIds.isNotEmpty()) {
61+
updateOutputsToSigned(conflictOutputIds)
62+
}
63+
}
4464
val remoteOutputIds: List<String> = remoteOutputs.map { it.outputId }
4565
val signedOutputIds: List<String> = if (remoteOutputIds.isEmpty()) emptyList() else findSignedOutputIds(remoteOutputIds)
4666
val outputsToInsert: List<WalletOutput> = if (signedOutputIds.isEmpty()) {
@@ -72,3 +92,12 @@ interface WalletOutputDao: BaseDao<WalletOutput> {
7292
return total
7393
}
7494
}
95+
96+
data class LocalUnspentOutputIndex(
97+
@ColumnInfo(name = "output_id")
98+
val outputId: String,
99+
@ColumnInfo(name = "transaction_hash")
100+
val transactionHash: String,
101+
@ColumnInfo(name = "output_index")
102+
val outputIndex: Long,
103+
)

0 commit comments

Comments
 (0)