Skip to content

Commit 361faa9

Browse files
committed
Revert "Do not send the previous tx for swap-in inputs"
This reverts commit c0a6d5a.
1 parent f2e1465 commit 361faa9

File tree

8 files changed

+37
-58
lines changed

8 files changed

+37
-58
lines changed

src/commonMain/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumMiniWallet.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ data class WalletState(val addresses: Map<String, List<Utxo>>) {
3232
data class Utxo(val txId: TxId, val outputIndex: Int, val blockHeight: Long, val previousTx: Transaction) {
3333
val outPoint = OutPoint(previousTx, outputIndex.toLong())
3434
val amount = previousTx.txOut[outputIndex].amount
35-
val txOut = previousTx.txOut[outputIndex]
3635
}
3736

3837
/**

src/commonMain/kotlin/fr/acinq/lightning/channel/InteractiveTx.kt

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,15 @@ sealed class InteractiveTxInput {
106106
sealed interface Incoming
107107

108108
sealed class Local : InteractiveTxInput(), Outgoing {
109-
abstract val previousTx: Transaction?
109+
abstract val previousTx: Transaction
110110
abstract val previousTxOutput: Long
111+
override val txOut: TxOut
112+
get() = previousTx.txOut[previousTxOutput.toInt()]
111113
}
112114

113115
/** A local-only input that funds the interactive transaction. */
114116
data class LocalOnly(override val serialId: Long, override val previousTx: Transaction, override val previousTxOutput: Long, override val sequence: UInt) : Local() {
115117
override val outPoint: OutPoint = OutPoint(previousTx, previousTxOutput)
116-
override val txOut: TxOut
117-
get() = previousTx.txOut[previousTxOutput.toInt()]
118118
}
119119

120120
/** A local input that funds the interactive transaction, coming from a 2-of-2 swap-in transaction. */
@@ -125,18 +125,12 @@ sealed class InteractiveTxInput {
125125

126126
data class LocalSwapIn(
127127
override val serialId: Long,
128+
override val previousTx: Transaction,
129+
override val previousTxOutput: Long,
128130
override val sequence: UInt,
129131
val swapInParams: TxAddInputTlv.SwapInParams
130132
) : Local() {
131-
override val outPoint: OutPoint
132-
get() = swapInParams.outPoint
133-
override val previousTx: Transaction?
134-
get() = null
135-
override val txOut: TxOut
136-
get() = swapInParams.txOut
137-
138-
override val previousTxOutput: Long
139-
get() = outPoint.index
133+
override val outPoint: OutPoint = OutPoint(previousTx, previousTxOutput)
140134
}
141135

142136
/**
@@ -153,15 +147,11 @@ sealed class InteractiveTxInput {
153147

154148
data class RemoteSwapIn(
155149
override val serialId: Long,
150+
override val outPoint: OutPoint,
151+
override val txOut: TxOut,
156152
override val sequence: UInt,
157153
val swapInParams: TxAddInputTlv.SwapInParams
158-
) : Remote() {
159-
override val txOut: TxOut
160-
get() = swapInParams.txOut
161-
162-
override val outPoint: OutPoint
163-
get() = swapInParams.outPoint
164-
}
154+
) : Remote()
165155

166156
/** The shared input can be added by us or by our peer, depending on who initiated the protocol. */
167157
data class Shared(
@@ -300,8 +290,10 @@ data class FundingContributions(val inputs: List<InteractiveTxInput.Outgoing>, v
300290

301291
else -> InteractiveTxInput.LocalSwapIn(
302292
0,
293+
i.previousTx.stripInputWitnesses(),
294+
i.outputIndex.toLong(),
303295
0xfffffffdU,
304-
TxAddInputTlv.SwapInParams(swapInKeys.userPublicKey, swapInKeys.remoteServerPublicKey, swapInKeys.userRefundPublicKey, swapInKeys.refundDelay, i.outPoint, i.txOut),
296+
TxAddInputTlv.SwapInParams(swapInKeys.userPublicKey, swapInKeys.remoteServerPublicKey, swapInKeys.userRefundPublicKey, swapInKeys.refundDelay),
305297
)
306298
}
307299
}
@@ -681,7 +673,7 @@ data class InteractiveTxSession(
681673
}
682674

683675
is InteractiveTxInput.LocalSwapIn -> {
684-
val swapInParams = TxAddInputTlv.SwapInParams(swapInKeys.userPublicKey, swapInKeys.remoteServerPublicKey, swapInKeys.userRefundPublicKey, swapInKeys.refundDelay, msg.value.outPoint, msg.value.txOut)
676+
val swapInParams = TxAddInputTlv.SwapInParams(swapInKeys.userPublicKey, swapInKeys.remoteServerPublicKey, swapInKeys.userRefundPublicKey, swapInKeys.refundDelay)
685677
TxAddInput(fundingParams.channelId, msg.value.serialId, msg.value.previousTx, msg.value.previousTxOutput, msg.value.sequence, TlvStream(swapInParams))
686678
}
687679

@@ -721,16 +713,14 @@ data class InteractiveTxSession(
721713
return Either.Left(InteractiveTxSessionAction.DuplicateSerialId(message.channelId, message.serialId))
722714
}
723715
// We check whether this is the shared input or a remote input.
724-
val input = when {
725-
message.previousTx == null && message.swapInParams != null -> {
726-
InteractiveTxInput.RemoteSwapIn(message.serialId, message.sequence, message.swapInParams)
727-
}
728-
message.previousTx == null -> {
716+
val input = when (message.previousTx) {
717+
null -> {
729718
val expectedSharedOutpoint = fundingParams.sharedInput?.info?.outPoint ?: return Either.Left(InteractiveTxSessionAction.PreviousTxMissing(message.channelId, message.serialId))
730719
val receivedSharedOutpoint = message.sharedInput ?: return Either.Left(InteractiveTxSessionAction.PreviousTxMissing(message.channelId, message.serialId))
731720
if (expectedSharedOutpoint != receivedSharedOutpoint) return Either.Left(InteractiveTxSessionAction.PreviousTxMissing(message.channelId, message.serialId))
732721
InteractiveTxInput.Shared(message.serialId, receivedSharedOutpoint, fundingParams.sharedInput.info.txOut.publicKeyScript, message.sequence, previousFunding.toLocal, previousFunding.toRemote)
733722
}
723+
734724
else -> {
735725
if (message.previousTx.txOut.size <= message.previousTxOutput) {
736726
return Either.Left(InteractiveTxSessionAction.InputOutOfBounds(message.channelId, message.serialId, message.previousTx.txid, message.previousTxOutput))
@@ -747,7 +737,7 @@ data class InteractiveTxSession(
747737
val txOut = message.previousTx.txOut[message.previousTxOutput.toInt()]
748738
when {
749739
message.swapInParams != null -> {
750-
InteractiveTxInput.RemoteSwapIn(message.serialId, message.sequence, message.swapInParams)
740+
InteractiveTxInput.RemoteSwapIn(message.serialId, outpoint, txOut, message.sequence, message.swapInParams)
751741
}
752742

753743
message.swapInParamsLegacy != null -> InteractiveTxInput.RemoteLegacySwapIn(message.serialId, outpoint, txOut, message.sequence, message.swapInParamsLegacy.userKey, message.swapInParamsLegacy.serverKey, message.swapInParamsLegacy.refundDelay)

src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Deserialization.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,8 @@ object Deserialization {
246246
)
247247
0x03 -> InteractiveTxInput.LocalSwapIn(
248248
serialId = readNumber(),
249+
previousTx = readTransaction(),
250+
previousTxOutput = readNumber(),
249251
sequence = readNumber().toUInt(),
250252
swapInParams = TxAddInputTlv.SwapInParams.read(this)
251253
)
@@ -270,6 +272,8 @@ object Deserialization {
270272
)
271273
0x03 -> InteractiveTxInput.RemoteSwapIn(
272274
serialId = readNumber(),
275+
outPoint = readOutPoint(),
276+
txOut = TxOut.read(readDelimitedByteArray()),
273277
sequence = readNumber().toUInt(),
274278
swapInParams = TxAddInputTlv.SwapInParams.read(this)
275279
)

src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Serialization.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,8 @@ object Serialization {
285285
is InteractiveTxInput.LocalSwapIn -> i.run {
286286
write(0x03)
287287
writeNumber(serialId)
288+
writeBtcObject(previousTx)
289+
writeNumber(previousTxOutput)
288290
writeNumber(sequence.toLong())
289291
swapInParams.write(this@writeLocalInteractiveTxInput)
290292
}
@@ -311,6 +313,8 @@ object Serialization {
311313
is InteractiveTxInput.RemoteSwapIn -> i.run {
312314
write(0x03)
313315
writeNumber(serialId)
316+
writeBtcObject(outPoint)
317+
writeBtcObject(txOut)
314318
writeNumber(sequence.toLong())
315319
swapInParams.write(this@writeRemoteInteractiveTxInput)
316320
}

src/commonMain/kotlin/fr/acinq/lightning/wire/InteractiveTxTlv.kt

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,19 +44,13 @@ sealed class TxAddInputTlv : Tlv {
4444
}
4545

4646
/** When adding a swap-in input to an interactive-tx, the user needs to provide the corresponding script parameters. */
47-
data class SwapInParams(val userKey: PublicKey, val serverKey: PublicKey, val userRefundKey: PublicKey, val refundDelay: Int, val outPoint: OutPoint, val txOut: TxOut) : TxAddInputTlv() {
47+
data class SwapInParams(val userKey: PublicKey, val serverKey: PublicKey, val userRefundKey: PublicKey, val refundDelay: Int) : TxAddInputTlv() {
4848
override val tag: Long get() = SwapInParams.tag
4949
override fun write(out: Output) {
5050
LightningCodecs.writeBytes(userKey.value, out)
5151
LightningCodecs.writeBytes(serverKey.value, out)
5252
LightningCodecs.writeBytes(userRefundKey.value, out)
5353
LightningCodecs.writeU32(refundDelay, out)
54-
val blob1 = OutPoint.write(outPoint)
55-
LightningCodecs.writeU16(blob1.size, out)
56-
LightningCodecs.writeBytes(blob1, out)
57-
val blob2 = TxOut.write(txOut)
58-
LightningCodecs.writeU16(blob2.size, out)
59-
LightningCodecs.writeBytes(blob2, out)
6054
}
6155

6256
companion object : TlvValueReader<SwapInParams> {
@@ -65,9 +59,7 @@ sealed class TxAddInputTlv : Tlv {
6559
PublicKey(LightningCodecs.bytes(input, 33)),
6660
PublicKey(LightningCodecs.bytes(input, 33)),
6761
PublicKey(LightningCodecs.bytes(input, 33)),
68-
LightningCodecs.u32(input),
69-
OutPoint.read(LightningCodecs.bytes(input, LightningCodecs.u16(input))),
70-
TxOut.read(LightningCodecs.bytes(input, LightningCodecs.u16(input)))
62+
LightningCodecs.u32(input)
7163
)
7264
}
7365
}

src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/SwapInManagerTestsCommon.kt

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -135,18 +135,16 @@ class SwapInManagerTestsCommon : LightningTestSuite() {
135135
@Ignore // FIXME
136136
fun `swap funds -- ignore inputs from pending channel`() {
137137
val (waitForFundingSigned, _) = WaitForFundingSignedTestsCommon.init()
138-
val inputs = waitForFundingSigned.state.signingSession.fundingTx.tx.localInputs
139138
val wallet = run {
140-
val parentTxs = inputs.associate { it.outPoint.txid to Transaction(version = 2, txIn = listOf(), txOut = listOf(it.txOut), lockTime = 0) }
141-
val utxos = inputs.map { i -> WalletState.Utxo(i.outPoint.txid, i.outPoint.index.toInt(), 100, parentTxs[i.outPoint.txid]!!) }
139+
val utxos = waitForFundingSigned.state.signingSession.fundingTx.tx.localInputs.map { i -> WalletState.Utxo(i.outPoint.txid, i.outPoint.index.toInt(), 100, i.previousTx) }
142140
WalletState(mapOf(dummyAddress to utxos))
143141
}
144142
val mgr = SwapInManager(listOf(waitForFundingSigned.state), logger)
145143
val cmd = SwapInCommand.TrySwapIn(currentBlockHeight = 150, wallet = wallet, swapInParams = SwapInParams(minConfirmations = 5, maxConfirmations = 720, refundDelay = 900), trustedTxs = emptySet())
146144
mgr.process(cmd).also { assertNull(it) }
147145

148146
// The pending channel is aborted: we can reuse those inputs.
149-
mgr.process(SwapInCommand.UnlockWalletInputs(inputs.map { it.outPoint }.toSet()))
147+
mgr.process(SwapInCommand.UnlockWalletInputs(wallet.utxos.map { it.outPoint }.toSet()))
150148
mgr.process(cmd).also { assertNotNull(it) }
151149
}
152150

@@ -158,16 +156,15 @@ class SwapInManagerTestsCommon : LightningTestSuite() {
158156
val inputs = alice1.commitments.active.map { it.localFundingStatus }.filterIsInstance<LocalFundingStatus.UnconfirmedFundingTx>().flatMap { it.sharedTx.tx.localInputs }
159157
assertEquals(3, inputs.size) // 1 initial funding input and 2 splice inputs
160158
val wallet = run {
161-
val parentTxs = inputs.associate { it.outPoint.txid to Transaction(version = 2, txIn = listOf(), txOut = listOf(it.txOut), lockTime = 0) }
162-
val utxos = inputs.map { i -> WalletState.Utxo(i.outPoint.txid, i.outPoint.index.toInt(), 100, parentTxs[i.outPoint.txid]!!) }
159+
val utxos = inputs.map { i -> WalletState.Utxo(i.outPoint.txid, i.outPoint.index.toInt(), 100, i.previousTx) }
163160
WalletState(mapOf(dummyAddress to utxos))
164161
}
165162
val mgr = SwapInManager(listOf(alice1.state), logger)
166163
val cmd = SwapInCommand.TrySwapIn(currentBlockHeight = 150, wallet = wallet, swapInParams = SwapInParams(minConfirmations = 5, maxConfirmations = 720, refundDelay = 900), trustedTxs = emptySet())
167164
mgr.process(cmd).also { assertNull(it) }
168165

169166
// The channel is aborted: we can reuse those inputs.
170-
mgr.process(SwapInCommand.UnlockWalletInputs(inputs.map { it.outPoint }.toSet()))
167+
mgr.process(SwapInCommand.UnlockWalletInputs(wallet.utxos.map { it.outPoint }.toSet()))
171168
mgr.process(cmd).also { result ->
172169
assertNotNull(result)
173170
assertEquals(3, result.walletInputs.size)
@@ -189,8 +186,7 @@ class SwapInManagerTestsCommon : LightningTestSuite() {
189186
assertEquals(1, alice3.commitments.all.size)
190187
assertIs<LocalFundingStatus.ConfirmedFundingTx>(alice3.commitments.latest.localFundingStatus)
191188
val wallet = run {
192-
val parentTxs = inputs.associate { it.outPoint.txid to Transaction(version = 2, txIn = listOf(), txOut = listOf(it.txOut), lockTime = 0) }
193-
val utxos = inputs.map { i -> WalletState.Utxo(i.outPoint.txid, i.outPoint.index.toInt(), 100, parentTxs[i.outPoint.txid]!!) }
189+
val utxos = inputs.map { i -> WalletState.Utxo(i.outPoint.txid, i.outPoint.index.toInt(), 100, i.previousTx) }
194190
WalletState(mapOf(dummyAddress to utxos))
195191
}
196192
val mgr = SwapInManager(listOf(alice3.state), logger)

src/commonTest/kotlin/fr/acinq/lightning/channel/InteractiveTxTestsCommon.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ class InteractiveTxTestsCommon : LightningTestSuite() {
101101
assertEquals(signedTx.lockTime, 42)
102102
assertEquals(signedTx.txIn.size, 4)
103103
assertEquals(signedTx.txOut.size, 3)
104-
Transaction.correctlySpends(signedTx, (sharedTxA.sharedTx.localInputs + sharedTxB.sharedTx.localInputs).associate { it.outPoint to it.txOut }, ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS)
104+
Transaction.correctlySpends(signedTx, (sharedTxA.sharedTx.localInputs + sharedTxB.sharedTx.localInputs).map { it.previousTx }, ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS)
105105
val feerate = Transactions.fee2rate(signedTxA.tx.fees, signedTx.weight())
106106
assertTrue(targetFeerate <= feerate && feerate <= targetFeerate * 1.25, "unexpected feerate (target=$targetFeerate actual=$feerate)")
107107
}
@@ -162,7 +162,7 @@ class InteractiveTxTestsCommon : LightningTestSuite() {
162162
assertEquals(signedTx.lockTime, 0)
163163
assertEquals(signedTx.txIn.size, 2)
164164
assertEquals(signedTx.txOut.size, 3)
165-
Transaction.correctlySpends(signedTx, (sharedTxA.sharedTx.localInputs + sharedTxB.sharedTx.localInputs).associate { it.outPoint to it.txOut }, ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS)
165+
Transaction.correctlySpends(signedTx, (sharedTxA.sharedTx.localInputs + sharedTxB.sharedTx.localInputs).map { it.previousTx }, ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS)
166166
val feerate = Transactions.fee2rate(signedTxB.tx.fees, signedTx.weight())
167167
assertTrue(targetFeerate <= feerate && feerate <= targetFeerate * 1.25, "unexpected feerate (target=$targetFeerate actual=$feerate)")
168168
}
@@ -214,7 +214,7 @@ class InteractiveTxTestsCommon : LightningTestSuite() {
214214
// The resulting transaction is valid and has the right feerate.
215215
val signedTxB = sharedTxB.sharedTx.sign(bob3, f.keyManagerB, f.fundingParamsB, f.localParamsB, f.localParamsA.nodeId).addRemoteSigs(f.channelKeysB, f.fundingParamsB, signedTxA.localSigs)
216216
assertNotNull(signedTxB)
217-
Transaction.correctlySpends(signedTxB.signedTx, (sharedTxA.sharedTx.localInputs + sharedTxB.sharedTx.localInputs).associate { it.outPoint to it.txOut }, ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS)
217+
Transaction.correctlySpends(signedTxB.signedTx, (sharedTxA.sharedTx.localInputs + sharedTxB.sharedTx.localInputs).map { it.previousTx }, ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS)
218218
val feerate = Transactions.fee2rate(signedTxB.tx.fees, signedTxB.signedTx.weight())
219219
assertTrue(targetFeerate <= feerate && feerate <= targetFeerate * 1.25, "unexpected feerate (target=$targetFeerate actual=$feerate)")
220220
}
@@ -279,7 +279,7 @@ class InteractiveTxTestsCommon : LightningTestSuite() {
279279
assertEquals(signedTx.lockTime, 0)
280280
assertEquals(signedTx.txIn.size, 2)
281281
assertEquals(signedTx.txOut.size, 2)
282-
Transaction.correctlySpends(signedTx, sharedTxA.sharedTx.localInputs.associate { it.outPoint to it.txOut }, ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS)
282+
Transaction.correctlySpends(signedTx, sharedTxA.sharedTx.localInputs.map { it.previousTx }, ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS)
283283
val feerate = Transactions.fee2rate(signedTxA.tx.fees, signedTx.weight())
284284
assertTrue(targetFeerate <= feerate && feerate <= targetFeerate * 1.25, "unexpected feerate (target=$targetFeerate actual=$feerate)")
285285
}

src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingConfirmedTestsCommon.kt

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -226,13 +226,7 @@ class WaitForFundingConfirmedTestsCommon : LightningTestSuite() {
226226
assertIs<RbfStatus.InProgress>(bob1.state.rbfStatus)
227227
assertEquals(actions1.size, 1)
228228
actions1.hasOutgoingMessage<TxAckRbf>()
229-
val input = alice.state.latestFundingTx.sharedTx.tx.localInputs.first()
230-
val tlvs = when (input) {
231-
is InteractiveTxInput.LocalSwapIn -> TlvStream<TxAddInputTlv>(input.swapInParams)
232-
is InteractiveTxInput.LocalLegacySwapIn -> TlvStream<TxAddInputTlv>(TxAddInputTlv.SwapInParamsLegacy(input.userKey, input.serverKey, input.refundDelay))
233-
is InteractiveTxInput.LocalOnly -> TlvStream.empty()
234-
}
235-
val txAddInput = input.run { TxAddInput(alice.channelId, serialId, previousTx, previousTxOutput, sequence, tlvs) }
229+
val txAddInput = alice.state.latestFundingTx.sharedTx.tx.localInputs.first().run { TxAddInput(alice.channelId, serialId, previousTx, previousTxOutput, sequence) }
236230
val (bob2, actions2) = bob1.process(ChannelCommand.MessageReceived(txAddInput))
237231
assertEquals(actions2.size, 1)
238232
actions2.hasOutgoingMessage<TxAddInput>()

0 commit comments

Comments
 (0)