Skip to content

Commit

Permalink
Support new watcher/client interface in lightning-kmp
Browse files Browse the repository at this point in the history
  • Loading branch information
dpad85 committed Jun 4, 2024
1 parent 94ffe70 commit c341ce5
Show file tree
Hide file tree
Showing 11 changed files with 33 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ import fr.acinq.bitcoin.ByteVector32
import fr.acinq.bitcoin.TxId
import fr.acinq.bitcoin.utils.Either
import fr.acinq.lightning.blockchain.electrum.ElectrumConnectionStatus
import fr.acinq.lightning.blockchain.electrum.getConfirmations
import fr.acinq.lightning.db.*
import fr.acinq.lightning.payment.FinalFailure
import fr.acinq.lightning.payment.OutgoingPaymentFailure
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import fr.acinq.phoenix.android.utils.datastore.SwapAddressFormat
import fr.acinq.phoenix.android.utils.datastore.UserPrefsRepository
import fr.acinq.phoenix.managers.PeerManager
import fr.acinq.phoenix.managers.WalletManager
import fr.acinq.phoenix.managers.phoenixSwapInWallet
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
Expand Down Expand Up @@ -111,7 +112,7 @@ class ReceiveViewModel(
viewModelScope.launch {
val swapAddressFormat = userPrefs.getSwapAddressFormat.first()
if (swapAddressFormat == SwapAddressFormat.LEGACY) {
val legacySwapInAddress = peerManager.getPeer().swapInWallet.legacySwapInAddress
val legacySwapInAddress = peerManager.getPeer().phoenixSwapInWallet.legacySwapInAddress
val image = BitmapHelper.generateBitmap(legacySwapInAddress).asImageBitmap()
currentSwapAddress = BitcoinAddressState.Show(0, legacySwapInAddress, image)
} else {
Expand All @@ -124,7 +125,7 @@ class ReceiveViewModel(
log.info("starting with swap-in address $startAddress:$startIndex")

// monitor the actual address from the swap-in wallet -- might take some time since the wallet must check all previous addresses
peerManager.getPeer().swapInWallet.swapInAddressFlow.filterNotNull().collect { (newAddress, newIndex) ->
peerManager.getPeer().phoenixSwapInWallet.swapInAddressFlow.filterNotNull().collect { (newAddress, newIndex) ->
log.info("swap-in wallet current address update: $newAddress:$newIndex")
val newImage = BitmapHelper.generateBitmap(newAddress).asImageBitmap()
internalDataRepository.saveLastUsedSwapIndex(newIndex)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class ChannelsWatcher(context: Context, workerParams: WorkerParameters) : Corout

// connect electrum (and only electrum), and wait for the watcher to catch-up
withTimeout(ELECTRUM_TIMEOUT_MILLIS) {
peer.watcher.openUpToDateFlow().first()
business.electrumWatcher.openUpToDateFlow().first()
}
log.info("electrum watcher is up-to-date")
business.appConnectionsDaemon?.decrementDisconnectCount(AppConnectionsDaemon.ControlTarget.Electrum)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import androidx.lifecycle.viewmodel.CreationExtras
import fr.acinq.lightning.blockchain.electrum.WalletState
import fr.acinq.phoenix.android.PhoenixApplication
import fr.acinq.phoenix.managers.PeerManager
import fr.acinq.phoenix.managers.phoenixSwapInWallet
import kotlinx.coroutines.launch
import org.slf4j.LoggerFactory

Expand All @@ -44,7 +45,7 @@ class SwapInAddressesViewModel(private val peerManager: PeerManager) : ViewModel
@UiThread
private fun monitorSwapAddresses() {
viewModelScope.launch {
peerManager.getPeer().swapInWallet.wallet.walletStateFlow.collect { walletState ->
peerManager.getPeer().phoenixSwapInWallet.wallet.walletStateFlow.collect { walletState ->
val newAddresses = walletState.addresses.toList().sortedByDescending {
val meta = it.second.meta
if (meta is WalletState.AddressMeta.Derived) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import fr.acinq.phoenix.legacy.utils.Prefs
import fr.acinq.phoenix.legacy.utils.ThemeHelper
import fr.acinq.phoenix.legacy.utils.Wallet
import fr.acinq.phoenix.managers.AppConnectionsDaemon
import fr.acinq.phoenix.managers.phoenixSwapInWallet
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import org.slf4j.Logger
Expand Down Expand Up @@ -498,7 +499,7 @@ fun WalletPaymentInfo.isLegacyMigration(peer: Peer?): Boolean? {
return when {
p !is ChannelCloseOutgoingPayment -> false
peer == null -> null
p.address == peer.swapInWallet.legacySwapInAddress && metadata.userDescription == LegacyMigrationHelper.migrationDescFlag -> true
p.address == peer.phoenixSwapInWallet.legacySwapInAddress && metadata.userDescription == LegacyMigrationHelper.migrationDescFlag -> true
else -> false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class PhoenixBusiness(
val chain: Chain = NodeParamsManager.chain

val electrumClient by lazy { ElectrumClient(scope = MainScope(), loggerFactory = loggerFactory, pingInterval = 30.seconds, rpcTimeout = 10.seconds) }
internal val electrumWatcher by lazy { ElectrumWatcher(electrumClient, MainScope(), loggerFactory) }
val electrumWatcher by lazy { ElectrumWatcher(electrumClient, MainScope(), loggerFactory) }

var appConnectionsDaemon: AppConnectionsDaemon? = null

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import fr.acinq.phoenix.controllers.config.CloseChannelsConfiguration.Model.Chan
import fr.acinq.phoenix.utils.Parser
import fr.acinq.phoenix.utils.extensions.localBalance
import fr.acinq.lightning.logging.info
import fr.acinq.phoenix.managers.phoenixFinalWallet
import kotlinx.coroutines.launch

class AppCloseChannelsConfigurationController(
Expand Down Expand Up @@ -93,7 +94,7 @@ class AppCloseChannelsConfigurationController(
val closableChannelsList = updatedChannelsList.filter {
isClosable(it.status)
}
val address = peer.finalWallet.finalAddress
val address = peer.phoenixFinalWallet.finalAddress
model(CloseChannelsConfiguration.Model.Ready(
channels = closableChannelsList,
address = address
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class BalanceManager(
*/
private suspend fun monitorSwapInBalance(peer: Peer) {
val swapInParams = peer.walletParams.swapInParams
combine(peer.currentTipFlow.filterNotNull(), peer.channelsFlow, peer.swapInWallet.wallet.walletStateFlow) { (currentBlockHeight, _), channels, swapInWallet ->
combine(peer.currentTipFlow.filterNotNull(), peer.channelsFlow, peer.phoenixSwapInWallet.wallet.walletStateFlow) { currentBlockHeight, channels, swapInWallet ->
val reservedInputs = SwapInManager.reservedWalletInputs(channels.values.filterIsInstance<PersistedChannelState>())
val walletWithoutReserved = swapInWallet.withoutReservedUtxos(reservedInputs)
walletWithoutReserved.withConfirmations(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package fr.acinq.phoenix.managers

import fr.acinq.bitcoin.TxId
import fr.acinq.lightning.blockchain.electrum.ElectrumClient
import fr.acinq.lightning.blockchain.electrum.getConfirmations
import fr.acinq.lightning.db.InboundLiquidityOutgoingPayment
import fr.acinq.lightning.db.SpliceCpfpOutgoingPayment
import fr.acinq.lightning.db.WalletPayment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ import fr.acinq.lightning.SwapInParams
import fr.acinq.lightning.TrampolineFees
import fr.acinq.lightning.UpgradeRequired
import fr.acinq.lightning.WalletParams
import fr.acinq.lightning.blockchain.electrum.ElectrumClient
import fr.acinq.lightning.blockchain.electrum.ElectrumWatcher
import fr.acinq.lightning.blockchain.electrum.FinalWallet
import fr.acinq.lightning.blockchain.electrum.IElectrumClient
import fr.acinq.lightning.blockchain.electrum.SwapInWallet
import fr.acinq.lightning.blockchain.electrum.WalletState
import fr.acinq.lightning.blockchain.fee.FeeratePerKw
import fr.acinq.lightning.channel.states.ChannelStateWithCommitments
Expand Down Expand Up @@ -42,6 +46,7 @@ class PeerManager(
private val databaseManager: DatabaseManager,
private val configurationManager: AppConfigurationManager,
private val notificationsManager: NotificationsManager,
private val electrumClient: ElectrumClient,
private val electrumWatcher: ElectrumWatcher,
) : CoroutineScope by CoroutineScope(CoroutineName("peer") + SupervisorJob() + Dispatchers.Main + CoroutineExceptionHandler { _, e ->
println("error in Peer coroutine scope: ${e.message}")
Expand All @@ -55,6 +60,7 @@ class PeerManager(
databaseManager = business.databaseManager,
configurationManager = business.appConfigurationManager,
notificationsManager = business.notificationsManager,
electrumClient = business.electrumClient,
electrumWatcher = business.electrumWatcher,
)

Expand All @@ -77,7 +83,7 @@ class PeerManager(
/** Flow of the peer's final wallet [WalletState.WalletWithConfirmations]. */
@OptIn(ExperimentalCoroutinesApi::class)
val finalWallet = peerState.filterNotNull().flatMapLatest { peer ->
combine(peer.currentTipFlow.filterNotNull(), peer.finalWallet.wallet.walletStateFlow) { (currentBlockHeight, _), wallet ->
combine(peer.currentTipFlow.filterNotNull(), peer.phoenixFinalWallet.wallet.walletStateFlow) { currentBlockHeight, wallet ->
wallet.withConfirmations(
currentBlockHeight = currentBlockHeight,
// the final wallet does not need to distinguish between weak/deep/locked txs
Expand All @@ -97,7 +103,7 @@ class PeerManager(
/** Flow of the peer's swap-in wallet [WalletState.WalletWithConfirmations]. */
@OptIn(ExperimentalCoroutinesApi::class)
val swapInWallet = peerState.filterNotNull().flatMapLatest { peer ->
combine(peer.currentTipFlow.filterNotNull(), peer.swapInWallet.wallet.walletStateFlow) { (currentBlockHeight, _), wallet ->
combine(peer.currentTipFlow.filterNotNull(), peer.phoenixSwapInWallet.wallet.walletStateFlow) { currentBlockHeight, wallet ->
wallet.withConfirmations(
currentBlockHeight = currentBlockHeight,
swapInParams = peer.walletParams.swapInParams
Expand Down Expand Up @@ -175,6 +181,7 @@ class PeerManager(
initTlvStream = initTlvs,
nodeParams = nodeParams,
walletParams = walletParams,
client = electrumClient,
watcher = electrumWatcher,
db = databaseManager.databases.filterNotNull().first(),
trustedSwapInTxs = startupParams.trustedSwapInTxs,
Expand Down Expand Up @@ -256,3 +263,12 @@ class PeerManager(
}
}
}


/** The peer's swap-in wallet for Phoenix is always not null, because the client is always an [IElectrumClient] (see how this Peer is built in `PeerManager.init`). */
val Peer.phoenixSwapInWallet: SwapInWallet
get() = this.swapInWallet!!

/** The peer's final wallet for Phoenix is always not null, because the client is always an [IElectrumClient] (see how this Peer is built in `PeerManager.init`). */
val Peer.phoenixFinalWallet: FinalWallet
get() = this.finalWallet!!
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import fr.acinq.phoenix.utils.Parser
import fr.acinq.phoenix.utils.extensions.isBeingCreated
import fr.acinq.lightning.logging.info
import fr.acinq.lightning.logging.warning
import fr.acinq.phoenix.managers.phoenixSwapInWallet
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
Expand Down Expand Up @@ -89,7 +90,7 @@ object IosMigrationHelper {
val log = loggerFactory.newLogger(this::class)

val peer = peerManager.getPeer()
val swapInAddress = peer.swapInWallet.swapInAddressFlow.filterNotNull().first().first
val swapInAddress = peer.phoenixSwapInWallet.swapInAddressFlow.filterNotNull().first().first
val closingScript = Parser.addressToPublicKeyScriptOrNull(chain, swapInAddress)
if (closingScript == null) {
log.warning { "aborting: could not get a valid closing script" }
Expand Down Expand Up @@ -139,7 +140,7 @@ object IosMigrationHelper {
log.info { "${closingTxs.size} channels closed to ${closingScript.toHex()}" }

// Wait for all UTXOs to arrive in swap-in wallet.
peer.swapInWallet.wallet.walletStateFlow
peer.phoenixSwapInWallet.wallet.walletStateFlow
.map { it.utxos.map { it.outPoint.txid } }
.first { txidsInWallet -> closingTxs.values.all { txid -> txidsInWallet.contains(txid) } }
log.info { "all mutual-close txids found in swap-in wallet" }
Expand Down

0 comments on commit c341ce5

Please sign in to comment.