Skip to content

Commit

Permalink
Remove the set of htlcs from the shared input
Browse files Browse the repository at this point in the history
 - no need to serialize htlcs in the shared input because we already serialize/deserialize the set of htlcs in the commitment

 - update the test to make sure even with a pending splice the encrypted backup can be sent
  • Loading branch information
remyers committed Dec 12, 2023
1 parent 38b4ec0 commit 1545b47
Show file tree
Hide file tree
Showing 9 changed files with 36 additions and 36 deletions.
23 changes: 12 additions & 11 deletions src/commonMain/kotlin/fr/acinq/lightning/channel/InteractiveTx.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,14 @@ import kotlinx.coroutines.CompletableDeferred
sealed class SharedFundingInput {
abstract val info: Transactions.InputInfo
abstract val weight: Int
abstract val localHtlcs: Set<DirectedHtlc>
abstract fun sign(channelKeys: KeyManager.ChannelKeys, tx: Transaction): ByteVector64

data class Multisig2of2(override val info: Transactions.InputInfo, val fundingTxIndex: Long, val remoteFundingPubkey: PublicKey, override val localHtlcs: Set<DirectedHtlc>) : SharedFundingInput() {
data class Multisig2of2(override val info: Transactions.InputInfo, val fundingTxIndex: Long, val remoteFundingPubkey: PublicKey) : SharedFundingInput() {

constructor(commitment: Commitment) : this(
info = commitment.commitInput,
fundingTxIndex = commitment.fundingTxIndex,
remoteFundingPubkey = commitment.remoteFundingPubkey,
localHtlcs = commitment.localCommit.spec.htlcs
remoteFundingPubkey = commitment.remoteFundingPubkey
)

// This value was computed assuming 73 bytes signatures (worst-case scenario).
Expand Down Expand Up @@ -136,7 +134,7 @@ sealed class InteractiveTxInput {
data class RemoteSwapIn(override val serialId: Long, override val outPoint: OutPoint, override val txOut: TxOut, override val sequence: UInt, val userKey: PublicKey, val serverKey: PublicKey, val refundDelay: Int) : Remote()

/** The shared input can be added by us or by our peer, depending on who initiated the protocol. */
data class Shared(override val serialId: Long, override val outPoint: OutPoint, override val sequence: UInt, val localAmount: MilliSatoshi, val remoteAmount: MilliSatoshi, val localHtlcs: Set<DirectedHtlc>) : InteractiveTxInput(), Incoming, Outgoing
data class Shared(override val serialId: Long, override val outPoint: OutPoint, override val sequence: UInt, val localAmount: MilliSatoshi, val remoteAmount: MilliSatoshi) : InteractiveTxInput(), Incoming, Outgoing
}

sealed class InteractiveTxOutput {
Expand Down Expand Up @@ -251,7 +249,7 @@ data class FundingContributions(val inputs: List<InteractiveTxInput.Outgoing>, v
}
}
}
val sharedInput = sharedUtxo?.let { (i, balances) -> listOf(InteractiveTxInput.Shared(0, i.info.outPoint, 0xfffffffdU, balances.toLocal, balances.toRemote, i.localHtlcs)) } ?: listOf()
val sharedInput = sharedUtxo?.let { (i, balances) -> listOf(InteractiveTxInput.Shared(0, i.info.outPoint, 0xfffffffdU, balances.toLocal, balances.toRemote)) } ?: listOf()
val localInputs = walletInputs.map { i -> InteractiveTxInput.LocalSwapIn(0, i.previousTx.stripInputWitnesses(), i.outputIndex.toLong(), 0xfffffffdU, swapInKeys.userPublicKey, swapInKeys.remoteServerPublicKey, swapInKeys.refundDelay) }
return if (params.isInitiator) {
Either.Right(sortFundingContributions(params, sharedInput + localInputs, sharedOutput + nonChangeOutputs + changeOutput))
Expand Down Expand Up @@ -281,7 +279,7 @@ data class FundingContributions(val inputs: List<InteractiveTxInput.Outgoing>, v
fun computeWeightPaid(isInitiator: Boolean, commitment: Commitment, walletInputs: List<WalletState.Utxo>, localOutputs: List<TxOut>): Int =
computeWeightPaid(
isInitiator,
SharedFundingInput.Multisig2of2(commitment.commitInput, commitment.fundingTxIndex, Transactions.PlaceHolderPubKey, commitment.localCommit.spec.htlcs),
SharedFundingInput.Multisig2of2(commitment.commitInput, commitment.fundingTxIndex, Transactions.PlaceHolderPubKey),
commitment.commitInput.txOut.publicKeyScript,
walletInputs,
localOutputs
Expand Down Expand Up @@ -468,6 +466,7 @@ data class InteractiveTxSession(
val previousFunding: SharedFundingInputBalances,
val toSend: List<Either<InteractiveTxInput.Outgoing, InteractiveTxOutput.Outgoing>>,
val previousTxs: List<SignedSharedTransaction> = listOf(),
val previousHtlcs: Set<DirectedHtlc>,
val localInputs: List<InteractiveTxInput.Outgoing> = listOf(),
val remoteInputs: List<InteractiveTxInput.Incoming> = listOf(),
val localOutputs: List<InteractiveTxOutput.Outgoing> = listOf(),
Expand Down Expand Up @@ -507,7 +506,8 @@ data class InteractiveTxSession(
fundingParams,
SharedFundingInputBalances(previousLocalBalance, previousRemoteBalance, previousHtlcs),
fundingContributions.inputs.map { i -> Either.Left<InteractiveTxInput.Outgoing, InteractiveTxOutput.Outgoing>(i) } + fundingContributions.outputs.map { o -> Either.Right<InteractiveTxInput.Outgoing, InteractiveTxOutput.Outgoing>(o) },
previousTxs
previousTxs,
previousHtlcs
)

val isComplete: Boolean = txCompleteSent && txCompleteReceived
Expand Down Expand Up @@ -557,7 +557,7 @@ data class InteractiveTxSession(
val expectedSharedOutpoint = fundingParams.sharedInput?.info?.outPoint ?: return Either.Left(InteractiveTxSessionAction.PreviousTxMissing(message.channelId, message.serialId))
val receivedSharedOutpoint = message.sharedInput ?: return Either.Left(InteractiveTxSessionAction.PreviousTxMissing(message.channelId, message.serialId))
if (expectedSharedOutpoint != receivedSharedOutpoint) return Either.Left(InteractiveTxSessionAction.PreviousTxMissing(message.channelId, message.serialId))
InteractiveTxInput.Shared(message.serialId, receivedSharedOutpoint, message.sequence, previousFunding.toLocal, previousFunding.toRemote, previousFunding.htlcs)
InteractiveTxInput.Shared(message.serialId, receivedSharedOutpoint, message.sequence, previousFunding.toLocal, previousFunding.toRemote)
}
else -> {
if (message.previousTx.txOut.size <= message.previousTxOutput) {
Expand Down Expand Up @@ -837,7 +837,8 @@ data class InteractiveTxSigningSession(
localCommitmentIndex: Long,
remoteCommitmentIndex: Long,
commitTxFeerate: FeeratePerKw,
remotePerCommitmentPoint: PublicKey
remotePerCommitmentPoint: PublicKey,
previousHtlcs: Set<DirectedHtlc>
): Either<ChannelException, Pair<InteractiveTxSigningSession, CommitSig>> {
val channelKeys = channelParams.localParams.channelKeys(keyManager)
val unsignedTx = sharedTx.buildUnsignedTx()
Expand All @@ -849,7 +850,7 @@ data class InteractiveTxSigningSession(
fundingAmount = sharedTx.sharedOutput.amount,
toLocal = sharedTx.sharedOutput.localAmount - localPushAmount + remotePushAmount,
toRemote = sharedTx.sharedOutput.remoteAmount - remotePushAmount + localPushAmount,
localHtlcs = sharedTx.sharedInput?.localHtlcs ?: setOf(),
localHtlcs = previousHtlcs,
localCommitmentIndex = localCommitmentIndex,
remoteCommitmentIndex = remoteCommitmentIndex,
commitTxFeerate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,8 @@ data class Normal(
localCommitmentIndex = parentCommitment.localCommit.index,
remoteCommitmentIndex = parentCommitment.remoteCommit.index,
parentCommitment.localCommit.spec.feerate,
parentCommitment.remoteCommit.remotePerCommitmentPoint
parentCommitment.remoteCommit.remotePerCommitmentPoint,
previousHtlcs = parentCommitment.localCommit.spec.htlcs
)
when (signingSession) {
is Either.Left -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ data class WaitForFundingConfirmed(
addAll(latestFundingTx.sharedTx.tx.localInputs.map { Either.Left(it) })
addAll(latestFundingTx.sharedTx.tx.localOutputs.map { Either.Right(it) })
}
val session = InteractiveTxSession(channelKeys(), keyManager.swapInOnChainWallet, fundingParams, SharedFundingInputBalances(0.msat, 0.msat, emptySet()), toSend, previousFundingTxs.map { it.sharedTx })
val session = InteractiveTxSession(channelKeys(), keyManager.swapInOnChainWallet, fundingParams, SharedFundingInputBalances(0.msat, 0.msat, emptySet()), toSend, previousFundingTxs.map { it.sharedTx }, commitments.latest.localCommit.spec.htlcs)
val nextState = this@WaitForFundingConfirmed.copy(rbfStatus = RbfStatus.InProgress(session))
Pair(nextState, listOf(ChannelAction.Message.Send(TxAckRbf(channelId, fundingParams.localContribution))))
}
Expand Down Expand Up @@ -179,7 +179,8 @@ data class WaitForFundingConfirmed(
localCommitmentIndex = replacedCommitment.localCommit.index,
remoteCommitmentIndex = replacedCommitment.remoteCommit.index,
replacedCommitment.localCommit.spec.feerate,
replacedCommitment.remoteCommit.remotePerCommitmentPoint
replacedCommitment.remoteCommit.remotePerCommitmentPoint,
replacedCommitment.localCommit.spec.htlcs
)
when (signingSession) {
is Either.Left -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ data class WaitForFundingCreated(
localCommitmentIndex = 0,
remoteCommitmentIndex = 0,
commitTxFeerate,
remoteFirstPerCommitmentPoint
remoteFirstPerCommitmentPoint,
emptySet()
)
when (signingSession) {
is Either.Left -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,7 @@ object Deserialization {
0x01 -> SharedFundingInput.Multisig2of2(
info = readInputInfo(),
fundingTxIndex = readNumber(),
remoteFundingPubkey = readPublicKey(),
localHtlcs = readCollection { readDirectedHtlc() }.toSet()
remoteFundingPubkey = readPublicKey()
)
else -> error("unknown discriminator $discriminator for class ${SharedFundingInput::class}")
}
Expand All @@ -206,8 +205,7 @@ object Deserialization {
outPoint = readOutPoint(),
sequence = readNumber().toUInt(),
localAmount = readNumber().msat,
remoteAmount = readNumber().msat,
localHtlcs = readCollection { readDirectedHtlc() }.toSet()
remoteAmount = readNumber().msat
)
else -> error("unknown discriminator $discriminator for class ${InteractiveTxInput.Shared::class}")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,6 @@ object Serialization {
writeInputInfo(i.info)
writeNumber(i.fundingTxIndex)
writePublicKey(i.remoteFundingPubkey)
writeCollection(i.localHtlcs) { writeDirectedHtlc(it) }
}
}

Expand All @@ -258,7 +257,6 @@ object Serialization {
writeNumber(sequence.toLong())
writeNumber(localAmount.toLong())
writeNumber(remoteAmount.toLong())
writeCollection(localHtlcs) { writeDirectedHtlc(it) }
}

private fun Output.writeLocalInteractiveTxInput(i: InteractiveTxInput.Local) = when (i) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1137,7 +1137,7 @@ class InteractiveTxTestsCommon : LightningTestSuite() {
val previousFundingAmount = (balanceA + balanceB).truncateToSatoshi()
val previousFundingTx = Transaction(2, listOf(TxIn(OutPoint(randomBytes32(), 0), 0)), listOf(TxOut(previousFundingAmount, fundingScript)), 0)
val inputInfo = Transactions.InputInfo(OutPoint(previousFundingTx, 0), previousFundingTx.txOut[0], redeemScript)
val sharedInputA = SharedFundingInput.Multisig2of2(inputInfo, fundingTxIndex, channelKeysB.fundingPubKey(fundingTxIndex), emptySet())
val sharedInputA = SharedFundingInput.Multisig2of2(inputInfo, fundingTxIndex, channelKeysB.fundingPubKey(fundingTxIndex))
val nextFundingPubkeyB = channelKeysB.fundingPubKey(fundingTxIndex + 1)
val fundingParamsA = InteractiveTxParams(channelId, true, fundingContributionA, fundingContributionB, sharedInputA, nextFundingPubkeyB, outputsA, lockTime, dustLimit, targetFeerate)
return FundingContributions.create(channelKeysA, swapInKeysA, fundingParamsA, Pair(sharedInputA, SharedFundingInputBalances(balanceA, balanceB, emptySet())), listOf(), outputsA, randomKey().publicKey())
Expand Down Expand Up @@ -1171,8 +1171,8 @@ class InteractiveTxTestsCommon : LightningTestSuite() {
val previousFundingAmount = (balanceA + balanceB).truncateToSatoshi()
val previousFundingTx = Transaction(2, listOf(TxIn(OutPoint(randomBytes32(), 0), 0)), listOf(TxOut(previousFundingAmount, fundingScript)), 0)
val inputInfo = Transactions.InputInfo(OutPoint(previousFundingTx, 0), previousFundingTx.txOut[0], redeemScript)
val sharedInputA = SharedFundingInput.Multisig2of2(inputInfo, fundingTxIndex, channelKeysB.fundingPubKey(fundingTxIndex), emptySet())
val sharedInputB = SharedFundingInput.Multisig2of2(inputInfo, fundingTxIndex, channelKeysA.fundingPubKey(fundingTxIndex), emptySet())
val sharedInputA = SharedFundingInput.Multisig2of2(inputInfo, fundingTxIndex, channelKeysB.fundingPubKey(fundingTxIndex))
val sharedInputB = SharedFundingInput.Multisig2of2(inputInfo, fundingTxIndex, channelKeysA.fundingPubKey(fundingTxIndex))
val nextFundingPubkeyA = channelKeysA.fundingPubKey(fundingTxIndex + 1)
val nextFundingPubkeyB = channelKeysB.fundingPubKey(fundingTxIndex + 1)
val fundingParamsA = InteractiveTxParams(channelId, true, fundingContributionA, fundingContributionB, sharedInputA, nextFundingPubkeyB, outputsA, lockTime, dustLimit, targetFeerate)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1295,7 +1295,7 @@ class SpliceTestsCommon : LightningTestSuite() {
return exchangeSpliceSigs(alice4, commitSigAlice, bob4, commitSigBob)
}

private fun initiateSpliceWithoutSigs(alice: LNChannel<Normal>, bob: LNChannel<Normal>, inAmounts: List<Satoshi> = emptyList(), pushAmount: MilliSatoshi = 0.msat, outAmount: Satoshi? = null): UnsignedSpliceFixture {
fun initiateSpliceWithoutSigs(alice: LNChannel<Normal>, bob: LNChannel<Normal>, inAmounts: List<Satoshi> = emptyList(), pushAmount: MilliSatoshi = 0.msat, outAmount: Satoshi? = null): UnsignedSpliceFixture {
val spliceIn_opt = if (inAmounts.isNotEmpty()) {
ChannelCommand.Commitment.Splice.Request.SpliceIn(createWalletWithFunds(alice.staticParams.nodeParams.keyManager, inAmounts), pushAmount)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import fr.acinq.lightning.Feature
import fr.acinq.lightning.Lightning.randomKey
import fr.acinq.lightning.MilliSatoshi
import fr.acinq.lightning.channel.*
import fr.acinq.lightning.channel.ChannelCommand
import fr.acinq.lightning.channel.TestsHelper.crossSign
import fr.acinq.lightning.channel.states.Normal
import fr.acinq.lightning.channel.states.PersistedChannelState
import fr.acinq.lightning.channel.states.SpliceTestsCommon.Companion.initiateSpliceWithoutSigs
import fr.acinq.lightning.serialization.Encryption.from
import fr.acinq.lightning.tests.utils.LightningTestSuite
import fr.acinq.lightning.utils.sat
import fr.acinq.lightning.utils.value
import fr.acinq.lightning.wire.CommitSig
import fr.acinq.lightning.wire.EncryptedChannelData
import fr.acinq.lightning.wire.LightningMessage
import fr.acinq.secp256k1.Hex
Expand Down Expand Up @@ -80,21 +81,20 @@ class StateSerializationTestsCommon : LightningTestSuite() {
fun commitSigSize(maxIncoming: Int, maxOutgoing: Int): Int {
val (alice1, bob1) = addHtlcs(alice, bob, MilliSatoshi(6000_000), maxOutgoing)
val (bob2, alice2) = addHtlcs(bob1, alice1, MilliSatoshi(6000_000), maxIncoming)
val (_, actions) = alice2.process(ChannelCommand.Commitment.Sign)
val commitSig0 = actions.findOutgoingMessage<CommitSig>()
val (alice3, bob3) = crossSign(alice2, bob2)

val (bob3, actions1) = bob2.process(ChannelCommand.MessageReceived(commitSig0))
val commandSign0 = actions1.findCommand<ChannelCommand.Commitment.Sign>()

val (_, actions2) = bob3.process(commandSign0)
val commitSig1 = actions2.findOutgoingMessage<CommitSig>()
assertIs<LNChannel<Normal>>(alice3)
assertIs<LNChannel<Normal>>(bob3)
val (_, commitSig0, _, commitSig1) = initiateSpliceWithoutSigs(alice3, bob3, listOf(50_000.sat))
assertFalse(commitSig1.channelData.isEmpty())

val bina = LightningMessage.encode(commitSig0)
val binb = LightningMessage.encode(commitSig1)
return max(bina.size, binb.size)
}

// with 6 incoming payments and 6 outgoing payments, we can still add our encrypted backup to commig_sig messages
assertTrue(commitSigSize(6, 6) < 65000)
// with 5 incoming payments and 5 outgoing payments, we can still add our encrypted backup to commig_sig messages
// and stay below the 65k limit for a future channel_reestablish message of unknown size
assertTrue(commitSigSize(5, 5) < 60_000)
}
}

0 comments on commit 1545b47

Please sign in to comment.