|
1 | 1 | package one.mixin.android.db.web3 |
2 | 2 |
|
3 | 3 | import androidx.room.Dao |
| 4 | +import androidx.room.ColumnInfo |
4 | 5 | import androidx.room.Query |
5 | 6 | import androidx.room.Transaction |
6 | 7 | import one.mixin.android.api.response.web3.WalletOutput |
@@ -39,8 +40,27 @@ interface WalletOutputDao: BaseDao<WalletOutput> { |
39 | 40 | @Query("UPDATE outputs SET status = 'signed' WHERE output_id IN (:outputIds)") |
40 | 41 | suspend fun updateOutputsToSigned(outputIds: List<String>): Int |
41 | 42 |
|
| 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 | + |
42 | 46 | @Transaction |
43 | 47 | 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 | + } |
44 | 64 | val remoteOutputIds: List<String> = remoteOutputs.map { it.outputId } |
45 | 65 | val signedOutputIds: List<String> = if (remoteOutputIds.isEmpty()) emptyList() else findSignedOutputIds(remoteOutputIds) |
46 | 66 | val outputsToInsert: List<WalletOutput> = if (signedOutputIds.isEmpty()) { |
@@ -72,3 +92,12 @@ interface WalletOutputDao: BaseDao<WalletOutput> { |
72 | 92 | return total |
73 | 93 | } |
74 | 94 | } |
| 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