Skip to content

Commit

Permalink
Add on-the-fly funding node events
Browse files Browse the repository at this point in the history
Add more node events for on-the-fly funding operations. This is mostly
useful for tests to wait until specific steps have been reached into
the protocol execution.
  • Loading branch information
t-bast committed Mar 25, 2024
1 parent 1b0f6ec commit 3c20b3f
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 14 deletions.
15 changes: 14 additions & 1 deletion src/commonMain/kotlin/fr/acinq/lightning/NodeEvents.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package fr.acinq.lightning

import fr.acinq.bitcoin.ByteVector32
import fr.acinq.bitcoin.OutPoint
import fr.acinq.bitcoin.Satoshi
import fr.acinq.lightning.blockchain.electrum.WalletState
import fr.acinq.lightning.channel.InteractiveTxParams
import fr.acinq.lightning.channel.SharedFundingInput
import fr.acinq.lightning.channel.TransactionFees
import fr.acinq.lightning.channel.states.ChannelStateWithCommitments
import fr.acinq.lightning.channel.states.Normal
import fr.acinq.lightning.channel.states.WaitForFundingCreated
Expand All @@ -12,13 +15,23 @@ import fr.acinq.lightning.utils.sum

sealed interface NodeEvents

sealed interface SwapInEvents : NodeEvents {
data class Requested(val walletInputs: List<WalletState.Utxo>) : SwapInEvents {
val totalAmount: Satoshi = walletInputs.map { it.amount }.sum()
}
data class Accepted(val inputs: Set<OutPoint>, val amount: Satoshi, val fees: TransactionFees) : SwapInEvents {
val receivedAmount: Satoshi = amount - fees.serviceFee - fees.miningFee
}
}

sealed interface ChannelEvents : NodeEvents {
data class Creating(val state: WaitForFundingCreated) : ChannelEvents
data class Created(val state: ChannelStateWithCommitments) : ChannelEvents
data class Confirmed(val state: Normal) : ChannelEvents
}

sealed interface LiquidityEvents : NodeEvents {
/** Amount of the liquidity event, before fees are paid. */
val amount: MilliSatoshi
val fee: MilliSatoshi
val source: Source
Expand All @@ -36,6 +49,7 @@ sealed interface LiquidityEvents : NodeEvents {
data class ChannelFundingCancelled(val paymentHash: ByteVector32) : Reason()
}
}
data class Accepted(override val amount: MilliSatoshi, override val fee: MilliSatoshi, override val source: Source) : LiquidityEvents
}

/** This is useful on iOS to ask the OS for time to finish some sensitive tasks. */
Expand All @@ -48,7 +62,6 @@ sealed interface SensitiveTaskEvents : NodeEvents {
}
data class TaskStarted(val id: TaskIdentifier) : SensitiveTaskEvents
data class TaskEnded(val id: TaskIdentifier) : SensitiveTaskEvents

}

/** This will be emitted in a corner case where the user restores a wallet on an older version of the app, which is unable to read the channel data. */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package fr.acinq.lightning.channel

import fr.acinq.bitcoin.*
import fr.acinq.lightning.ChannelEvents
import fr.acinq.lightning.CltvExpiry
import fr.acinq.lightning.MilliSatoshi
import fr.acinq.lightning.NodeEvents
import fr.acinq.lightning.blockchain.Watch
import fr.acinq.lightning.channel.states.PersistedChannelState
import fr.acinq.lightning.db.ChannelClosingType
Expand Down Expand Up @@ -134,8 +134,8 @@ sealed class ChannelAction {
}
}

data class EmitEvent(val event: ChannelEvents) : ChannelAction()
data class EmitEvent(val event: NodeEvents) : ChannelAction()

object Disconnect : ChannelAction()
data object Disconnect : ChannelAction()
// @formatter:on
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import fr.acinq.bitcoin.Bitcoin
import fr.acinq.bitcoin.SigHash
import fr.acinq.bitcoin.TxId
import fr.acinq.bitcoin.utils.Either
import fr.acinq.lightning.Feature
import fr.acinq.lightning.Features
import fr.acinq.lightning.ShortChannelId
import fr.acinq.lightning.*
import fr.acinq.lightning.blockchain.BITCOIN_FUNDING_DEPTHOK
import fr.acinq.lightning.blockchain.WatchConfirmed
import fr.acinq.lightning.blockchain.WatchEventConfirmed
Expand Down Expand Up @@ -912,6 +910,12 @@ data class Normal(
val miningFees = action.fundingTx.sharedTx.tx.localFees.truncateToSatoshi() + liquidityLease.fees.miningFee
add(ChannelAction.Storage.StoreOutgoingPayment.ViaInboundLiquidityRequest(txId = action.fundingTx.txId, miningFees = miningFees, lease = liquidityLease))
}
addAll(origins.map { origin ->
when (origin) {
is Origin.OffChainPayment -> ChannelAction.EmitEvent(LiquidityEvents.Accepted(origin.amount, origin.fees.total.toMilliSatoshi(), LiquidityEvents.Source.OffChainPayment))
is Origin.OnChainWallet -> ChannelAction.EmitEvent(SwapInEvents.Accepted(origin.inputs, origin.amount.truncateToSatoshi(), origin.fees))
}
})
if (staticParams.useZeroConf) {
logger.info { "channel is using 0-conf, sending splice_locked right away" }
val spliceLocked = SpliceLocked(channelId, action.fundingTx.txId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import fr.acinq.bitcoin.ByteVector32
import fr.acinq.bitcoin.PublicKey
import fr.acinq.bitcoin.crypto.Pack
import fr.acinq.bitcoin.utils.Either
import fr.acinq.lightning.ChannelEvents
import fr.acinq.lightning.MilliSatoshi
import fr.acinq.lightning.ShortChannelId
import fr.acinq.lightning.*
import fr.acinq.lightning.blockchain.BITCOIN_FUNDING_DEPTHOK
import fr.acinq.lightning.blockchain.WatchConfirmed
import fr.acinq.lightning.channel.*
Expand Down Expand Up @@ -131,6 +129,12 @@ data class WaitForFundingSigned(
origin = channelOrigin
)
)
channelOrigin?.let {
when (it) {
is Origin.OffChainPayment -> add(ChannelAction.EmitEvent(LiquidityEvents.Accepted(it.amount, it.fees.total.toMilliSatoshi(), LiquidityEvents.Source.OffChainPayment)))
is Origin.OnChainWallet -> add(ChannelAction.EmitEvent(SwapInEvents.Accepted(it.inputs, it.amount.truncateToSatoshi(), it.fees)))
}
}
}
return if (staticParams.useZeroConf) {
logger.info { "channel is using 0-conf, we won't wait for the funding tx to confirm" }
Expand Down
2 changes: 2 additions & 0 deletions src/commonMain/kotlin/fr/acinq/lightning/io/Peer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -1138,6 +1138,7 @@ class Peer(
}
}
input.send(WrappedChannelCommand(channel.channelId, spliceCommand))
nodeParams._nodeEvents.emit(SwapInEvents.Requested(cmd.walletInputs))
}
}
}
Expand Down Expand Up @@ -1197,6 +1198,7 @@ class Peer(
val msg = actions.filterIsInstance<ChannelAction.Message.Send>().map { it.message }.filterIsInstance<OpenDualFundedChannel>().first()
_channels = _channels + (msg.temporaryChannelId to state)
processActions(msg.temporaryChannelId, peerConnection, actions)
nodeParams._nodeEvents.emit(SwapInEvents.Requested(cmd.walletInputs))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class WaitForFundingSignedTestsCommon : LightningTestSuite() {
val (alice, _, _, commitSigBob) = init(aliceFundingAmount = 0.sat, alicePushAmount = 0.msat, bobPushAmount = 50_000_000.msat, channelOrigin = channelOrigin)
val (alice1, actionsAlice1) = alice.process(ChannelCommand.MessageReceived(commitSigBob))
assertIs<WaitForFundingConfirmed>(alice1.state)
assertEquals(actionsAlice1.size, 5)
assertEquals(actionsAlice1.size, 6)
actionsAlice1.hasOutgoingMessage<TxSignatures>()
actionsAlice1.has<ChannelAction.Storage.StoreState>()
actionsAlice1.find<ChannelAction.Storage.StoreIncomingPayment.ViaNewChannel>().also {
Expand All @@ -148,7 +148,9 @@ class WaitForFundingSignedTestsCommon : LightningTestSuite() {
assertEquals(alice1.commitments.latest.fundingTxId, it.txId)
}
actionsAlice1.hasWatch<WatchConfirmed>()
actionsAlice1.has<ChannelAction.EmitEvent>()
val events = actionsAlice1.filterIsInstance<ChannelAction.EmitEvent>().map { it.event }
assertTrue(events.any { it is ChannelEvents.Created })
assertTrue(events.any { it is LiquidityEvents.Accepted })
}

@Test
Expand All @@ -157,7 +159,7 @@ class WaitForFundingSignedTestsCommon : LightningTestSuite() {
val (alice, _, _, commitSigBob) = init(aliceFundingAmount = 200_000.sat, alicePushAmount = 0.msat, bobFundingAmount = 500_000.sat, channelOrigin = channelOrigin)
val (alice1, actionsAlice1) = alice.process(ChannelCommand.MessageReceived(commitSigBob))
assertIs<WaitForFundingConfirmed>(alice1.state)
assertEquals(actionsAlice1.size, 5)
assertEquals(actionsAlice1.size, 6)
actionsAlice1.hasOutgoingMessage<TxSignatures>()
actionsAlice1.has<ChannelAction.Storage.StoreState>()
actionsAlice1.find<ChannelAction.Storage.StoreIncomingPayment.ViaNewChannel>().also {
Expand All @@ -166,7 +168,9 @@ class WaitForFundingSignedTestsCommon : LightningTestSuite() {
assertTrue(it.localInputs.isNotEmpty())
}
actionsAlice1.hasWatch<WatchConfirmed>()
actionsAlice1.has<ChannelAction.EmitEvent>()
val events = actionsAlice1.filterIsInstance<ChannelAction.EmitEvent>().map { it.event }
assertTrue(events.any { it is ChannelEvents.Created })
assertTrue(events.any { it is SwapInEvents.Accepted })
}

@Test
Expand Down

0 comments on commit 3c20b3f

Please sign in to comment.