Skip to content

Commit f8babed

Browse files
authored
Rework XxxCommitPublishedTypes (#229)
Re-work the `CommitPublished` types to work better with anchor outputs. We previously stored the txs spending utxos that we could claim: this doesn't make sense anymore if these txs may be RBF-ed, because the final tx will be different from the initial one. We instead track what `OutPoint`s we can claim, and the information necessary to claim them. We also add information on mutual close txs to immediately identify our output and its amount: this makes auditing how much sats we'll get back much easier for wallets.
1 parent dfe40be commit f8babed

File tree

18 files changed

+1397
-845
lines changed

18 files changed

+1397
-845
lines changed

src/commonMain/kotlin/fr/acinq/eclair/channel/Channel.kt

Lines changed: 94 additions & 67 deletions
Large diffs are not rendered by default.

src/commonMain/kotlin/fr/acinq/eclair/channel/ChannelTypes.kt

Lines changed: 144 additions & 92 deletions
Large diffs are not rendered by default.

src/commonMain/kotlin/fr/acinq/eclair/channel/Commitments.kt

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import fr.acinq.eclair.crypto.ShaChain
1313
import fr.acinq.eclair.payment.OutgoingPacket
1414
import fr.acinq.eclair.transactions.CommitmentSpec
1515
import fr.acinq.eclair.transactions.Transactions
16-
import fr.acinq.eclair.transactions.Transactions.TransactionWithInputInfo
17-
import fr.acinq.eclair.transactions.Transactions.TransactionWithInputInfo.*
16+
import fr.acinq.eclair.transactions.Transactions.TransactionWithInputInfo.CommitTx
17+
import fr.acinq.eclair.transactions.Transactions.TransactionWithInputInfo.HtlcTx
1818
import fr.acinq.eclair.transactions.Transactions.commitTxFee
1919
import fr.acinq.eclair.transactions.Transactions.commitTxFeeMsat
2020
import fr.acinq.eclair.transactions.Transactions.htlcOutputFee
@@ -33,7 +33,7 @@ data class LocalChanges(val proposed: List<UpdateMessage>, val signed: List<Upda
3333
}
3434

3535
data class RemoteChanges(val proposed: List<UpdateMessage>, val acked: List<UpdateMessage>, val signed: List<UpdateMessage>)
36-
data class HtlcTxAndSigs(val txinfo: TransactionWithInputInfo, val localSig: ByteVector64, val remoteSig: ByteVector64)
36+
data class HtlcTxAndSigs(val txinfo: HtlcTx, val localSig: ByteVector64, val remoteSig: ByteVector64)
3737
data class PublishableTxs(val commitTx: CommitTx, val htlcTxsAndSigs: List<HtlcTxAndSigs>)
3838
data class LocalCommit(val index: Long, val spec: CommitmentSpec, val publishableTxs: PublishableTxs)
3939
data class RemoteCommit(val index: Long, val spec: CommitmentSpec, val txid: ByteVector32, val remotePerCommitmentPoint: PublicKey)
@@ -459,10 +459,10 @@ data class Commitments(
459459

460460
// remote commitment will include all local changes + remote acked changes
461461
val spec = CommitmentSpec.reduce(remoteCommit.spec, remoteChanges.acked, localChanges.proposed)
462-
val (remoteCommitTx, htlcTimeoutTxs, htlcSuccessTxs) = makeRemoteTxs(keyManager, channelVersion, remoteCommit.index + 1, localParams, remoteParams, commitInput, remoteNextPerCommitmentPoint, spec)
462+
val (remoteCommitTx, htlcTxs) = makeRemoteTxs(keyManager, channelVersion, remoteCommit.index + 1, localParams, remoteParams, commitInput, remoteNextPerCommitmentPoint, spec)
463463
val sig = keyManager.sign(remoteCommitTx, keyManager.fundingPublicKey(localParams.fundingKeyPath))
464464

465-
val sortedHtlcTxs: List<TransactionWithInputInfo> = (htlcTimeoutTxs + htlcSuccessTxs).sortedBy { it.input.outPoint.index }
465+
val sortedHtlcTxs: List<HtlcTx> = htlcTxs.sortedBy { it.input.outPoint.index }
466466
val channelKeyPath = keyManager.channelKeyPath(localParams, channelVersion)
467467
// we sign our peer's HTLC txs with SIGHASH_SINGLE || SIGHASH_ANYONECANPAY
468468
val htlcSigs = sortedHtlcTxs.map { keyManager.sign(it, keyManager.htlcPoint(channelKeyPath), remoteNextPerCommitmentPoint, SigHash.SIGHASH_SINGLE or SigHash.SIGHASH_ANYONECANPAY) }
@@ -506,7 +506,7 @@ data class Commitments(
506506
val spec = CommitmentSpec.reduce(localCommit.spec, localChanges.acked, remoteChanges.proposed)
507507
val channelKeyPath = keyManager.channelKeyPath(localParams, channelVersion)
508508
val localPerCommitmentPoint = keyManager.commitmentPoint(channelKeyPath, localCommit.index + 1)
509-
val (localCommitTx, htlcTimeoutTxs, htlcSuccessTxs) = makeLocalTxs(keyManager, channelVersion, localCommit.index + 1, localParams, remoteParams, commitInput, localPerCommitmentPoint, spec)
509+
val (localCommitTx, htlcTxs) = makeLocalTxs(keyManager, channelVersion, localCommit.index + 1, localParams, remoteParams, commitInput, localPerCommitmentPoint, spec)
510510
val sig = keyManager.sign(localCommitTx, keyManager.fundingPublicKey(localParams.fundingKeyPath))
511511

512512
log.info {
@@ -524,30 +524,29 @@ data class Commitments(
524524
}
525525
}
526526

527-
val sortedHtlcTxs: List<TransactionWithInputInfo> = (htlcTimeoutTxs + htlcSuccessTxs).sortedBy { it.input.outPoint.index }
527+
val sortedHtlcTxs: List<HtlcTx> = htlcTxs.sortedBy { it.input.outPoint.index }
528528
if (commit.htlcSignatures.size != sortedHtlcTxs.size) {
529529
return Either.Left(HtlcSigCountMismatch(channelId, sortedHtlcTxs.size, commit.htlcSignatures.size))
530530
}
531531
val htlcSigs = sortedHtlcTxs.map { keyManager.sign(it, keyManager.htlcPoint(channelKeyPath), localPerCommitmentPoint, SigHash.SIGHASH_ALL) }
532532
val remoteHtlcPubkey = Generators.derivePubKey(remoteParams.htlcBasepoint, localPerCommitmentPoint)
533533
// combine the sigs to make signed txs
534-
val htlcTxsAndSigs = Triple(sortedHtlcTxs, htlcSigs, commit.htlcSignatures).zipped().mapNotNull { (htlcTx, localSig, remoteSig) ->
534+
val htlcTxsAndSigs = Triple(sortedHtlcTxs, htlcSigs, commit.htlcSignatures).zipped().map { (htlcTx, localSig, remoteSig) ->
535535
when (htlcTx) {
536-
is HtlcTimeoutTx -> {
536+
is HtlcTx.HtlcTimeoutTx -> {
537537
if (Transactions.checkSpendable(Transactions.addSigs(htlcTx, localSig, remoteSig)).isFailure) {
538538
return Either.Left(InvalidHtlcSignature(channelId, htlcTx.tx))
539539
}
540540
HtlcTxAndSigs(htlcTx, localSig, remoteSig)
541541
}
542-
is HtlcSuccessTx -> {
542+
is HtlcTx.HtlcSuccessTx -> {
543543
// we can't check that htlc-success tx are spendable because we need the payment preimage; thus we only check the remote sig
544544
// which was created with SIGHASH_SINGLE || SIGHASH_ANYONECANPAY
545545
if (!Transactions.checkSig(htlcTx, remoteSig, remoteHtlcPubkey, SigHash.SIGHASH_SINGLE or SigHash.SIGHASH_ANYONECANPAY)) {
546546
return Either.Left(InvalidHtlcSignature(channelId, htlcTx.tx))
547547
}
548548
HtlcTxAndSigs(htlcTx, localSig, remoteSig)
549549
}
550-
else -> null
551550
}
552551
}
553552

@@ -633,7 +632,7 @@ data class Commitments(
633632
commitmentInput: Transactions.InputInfo,
634633
localPerCommitmentPoint: PublicKey,
635634
spec: CommitmentSpec
636-
): Triple<CommitTx, List<HtlcTimeoutTx>, List<HtlcSuccessTx>> {
635+
): Pair<CommitTx, List<HtlcTx>> {
637636
val channelKeyPath = keyManager.channelKeyPath(localParams, channelVersion)
638637
val localDelayedPaymentPubkey = Generators.derivePubKey(keyManager.delayedPaymentPoint(channelKeyPath).publicKey, localPerCommitmentPoint)
639638
val localHtlcPubkey = Generators.derivePubKey(keyManager.htlcPoint(channelKeyPath).publicKey, localPerCommitmentPoint)
@@ -655,8 +654,8 @@ data class Commitments(
655654
spec
656655
)
657656
val commitTx = Transactions.makeCommitTx(commitmentInput, commitTxNumber, localPaymentBasepoint, remoteParams.paymentBasepoint, localParams.isFunder, outputs)
658-
val (htlcTimeoutTxs, htlcSuccessTxs) = Transactions.makeHtlcTxs(commitTx.tx, localParams.dustLimit, localRevocationPubkey, remoteParams.toSelfDelay, localDelayedPaymentPubkey, spec.feerate, outputs)
659-
return Triple(commitTx, htlcTimeoutTxs, htlcSuccessTxs)
657+
val htlcTxs = Transactions.makeHtlcTxs(commitTx.tx, localParams.dustLimit, localRevocationPubkey, remoteParams.toSelfDelay, localDelayedPaymentPubkey, spec.feerate, outputs)
658+
return Pair(commitTx, htlcTxs)
660659
}
661660

662661
fun makeRemoteTxs(
@@ -666,7 +665,7 @@ data class Commitments(
666665
remoteParams: RemoteParams, commitmentInput: Transactions.InputInfo,
667666
remotePerCommitmentPoint: PublicKey,
668667
spec: CommitmentSpec
669-
): Triple<CommitTx, List<HtlcTimeoutTx>, List<HtlcSuccessTx>> {
668+
): Pair<CommitTx, List<HtlcTx>> {
670669
val channelKeyPath = keyManager.channelKeyPath(localParams, channelVersion)
671670
val localPaymentPubkey = keyManager.paymentPoint(channelKeyPath).publicKey
672671
val localHtlcPubkey = Generators.derivePubKey(keyManager.htlcPoint(channelKeyPath).publicKey, remotePerCommitmentPoint)
@@ -688,8 +687,8 @@ data class Commitments(
688687
)
689688
// NB: we are creating the remote commit tx, so local/remote parameters are inverted.
690689
val commitTx = Transactions.makeCommitTx(commitmentInput, commitTxNumber, remoteParams.paymentBasepoint, localPaymentPubkey, !localParams.isFunder, outputs)
691-
val (htlcTimeoutTxs, htlcSuccessTxs) = Transactions.makeHtlcTxs(commitTx.tx, remoteParams.dustLimit, remoteRevocationPubkey, localParams.toSelfDelay, remoteDelayedPaymentPubkey, spec.feerate, outputs)
692-
return Triple(commitTx, htlcTimeoutTxs, htlcSuccessTxs)
690+
val htlcTxs = Transactions.makeHtlcTxs(commitTx.tx, remoteParams.dustLimit, remoteRevocationPubkey, localParams.toSelfDelay, remoteDelayedPaymentPubkey, spec.feerate, outputs)
691+
return Pair(commitTx, htlcTxs)
693692
}
694693
}
695694
}

0 commit comments

Comments
 (0)