1
0
Fork 0
mirror of https://github.com/ACINQ/eclair.git synced 2025-02-22 22:25:26 +01:00

Refactor Closing.claimRemoteCommitMainOutput() (#2191)

Building an inconsistent intermediate `RemoteCommitPublished` object was error-prone and defeats the purpose of strong typing.

We also handle the `paysDirectlyToWallet` case directly in the method, which enables a nice factorization and better contains this now deprecated feature.
This commit is contained in:
Pierre-Marie Padiou 2022-03-01 13:27:17 +01:00 committed by GitHub
parent 068b1393e1
commit 8f7c6ed68e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 40 additions and 52 deletions

View file

@ -2526,17 +2526,15 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder, remo
private def handleRemoteSpentFuture(commitTx: Transaction, d: DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT) = {
log.warning(s"they published their future commit (because we asked them to) in txid=${commitTx.txid}")
context.system.eventStream.publish(TransactionPublished(d.channelId, remoteNodeId, commitTx, Closing.commitTxFee(d.commitments.commitInput, commitTx, d.commitments.localParams.isFunder), "future-remote-commit"))
d.commitments.channelFeatures match {
case ct if ct.paysDirectlyToWallet =>
val remoteCommitPublished = RemoteCommitPublished(commitTx, None, Map.empty, List.empty, Map.empty)
val nextData = DATA_CLOSING(d.commitments, fundingTx = None, waitingSince = nodeParams.currentBlockHeight, Nil, futureRemoteCommitPublished = Some(remoteCommitPublished))
goto(CLOSING) using nextData storing() // we don't need to claim our main output in the remote commit because it already spends to our wallet address
case _ =>
val remotePerCommitmentPoint = d.remoteChannelReestablish.myCurrentPerCommitmentPoint
val remoteCommitPublished = Helpers.Closing.claimRemoteCommitMainOutput(keyManager, d.commitments, remotePerCommitmentPoint, commitTx, nodeParams.onChainFeeConf.feeEstimator, nodeParams.onChainFeeConf.feeTargets)
val nextData = DATA_CLOSING(d.commitments, fundingTx = None, waitingSince = nodeParams.currentBlockHeight, Nil, futureRemoteCommitPublished = Some(remoteCommitPublished))
goto(CLOSING) using nextData storing() calling doPublish(remoteCommitPublished, d.commitments)
}
val remotePerCommitmentPoint = d.remoteChannelReestablish.myCurrentPerCommitmentPoint
val remoteCommitPublished = RemoteCommitPublished(
commitTx = commitTx,
claimMainOutputTx = Helpers.Closing.claimRemoteCommitMainOutput(keyManager, d.commitments, remotePerCommitmentPoint, commitTx, nodeParams.onChainFeeConf.feeEstimator, nodeParams.onChainFeeConf.feeTargets),
claimHtlcTxs = Map.empty,
claimAnchorTxs = List.empty,
irrevocablySpent = Map.empty)
val nextData = DATA_CLOSING(d.commitments, fundingTx = None, waitingSince = nodeParams.currentBlockHeight, Nil, futureRemoteCommitPublished = Some(remoteCommitPublished))
goto(CLOSING) using nextData storing() calling doPublish(remoteCommitPublished, d.commitments)
}
private def handleRemoteSpentNext(commitTx: Transaction, d: HasCommitments) = {

View file

@ -793,60 +793,50 @@ object Helpers {
}
).flatten
if (commitments.channelFeatures.paysDirectlyToWallet) {
RemoteCommitPublished(
commitTx = tx,
claimMainOutputTx = None,
claimHtlcTxs = htlcTxs,
claimAnchorTxs = claimAnchorTxs,
irrevocablySpent = Map.empty
)
} else {
claimRemoteCommitMainOutput(keyManager, commitments, remoteCommit.remotePerCommitmentPoint, tx, feeEstimator, feeTargets).copy(
claimHtlcTxs = htlcTxs,
claimAnchorTxs = claimAnchorTxs,
)
}
RemoteCommitPublished(
commitTx = tx,
claimMainOutputTx = claimRemoteCommitMainOutput(keyManager, commitments, remoteCommit.remotePerCommitmentPoint, tx, feeEstimator, feeTargets),
claimHtlcTxs = htlcTxs,
claimAnchorTxs = claimAnchorTxs,
irrevocablySpent = Map.empty
)
}
/**
* Claim our main output only (not necessary if option_static_remotekey was negotiated).
* Claim our main output only
*
* @param commitments either our current commitment data in case of usual remote uncooperative closing
* or our outdated commitment data in case of data loss protection procedure; in any case it is used only
* to get some constant parameters, not commitment data
* @param remotePerCommitmentPoint the remote perCommitmentPoint corresponding to this commitment
* @param tx the remote commitment transaction that has just been published
* @return a transaction claiming our main output
* @return an optional [[ClaimRemoteCommitMainOutputTx]] transaction claiming our main output
*/
def claimRemoteCommitMainOutput(keyManager: ChannelKeyManager, commitments: Commitments, remotePerCommitmentPoint: PublicKey, tx: Transaction, feeEstimator: FeeEstimator, feeTargets: FeeTargets)(implicit log: LoggingAdapter): RemoteCommitPublished = {
val channelKeyPath = keyManager.keyPath(commitments.localParams, commitments.channelConfig)
val localPubkey = Generators.derivePubKey(keyManager.paymentPoint(channelKeyPath).publicKey, remotePerCommitmentPoint)
val localPaymentPoint = keyManager.paymentPoint(channelKeyPath).publicKey
val feeratePerKwMain = feeEstimator.getFeeratePerKw(feeTargets.claimMainBlockTarget)
def claimRemoteCommitMainOutput(keyManager: ChannelKeyManager, commitments: Commitments, remotePerCommitmentPoint: PublicKey, tx: Transaction, feeEstimator: FeeEstimator, feeTargets: FeeTargets)(implicit log: LoggingAdapter): Option[ClaimRemoteCommitMainOutputTx] = {
if (commitments.channelFeatures.paysDirectlyToWallet) {
// the commitment tx sends funds directly to our wallet, no claim tx needed
None
} else {
val channelKeyPath = keyManager.keyPath(commitments.localParams, commitments.channelConfig)
val localPubkey = Generators.derivePubKey(keyManager.paymentPoint(channelKeyPath).publicKey, remotePerCommitmentPoint)
val localPaymentPoint = keyManager.paymentPoint(channelKeyPath).publicKey
val feeratePerKwMain = feeEstimator.getFeeratePerKw(feeTargets.claimMainBlockTarget)
val mainTx = commitments.commitmentFormat match {
case DefaultCommitmentFormat => withTxGenerationLog("remote-main") {
Transactions.makeClaimP2WPKHOutputTx(tx, commitments.localParams.dustLimit, localPubkey, commitments.localParams.defaultFinalScriptPubKey, feeratePerKwMain).map(claimMain => {
val sig = keyManager.sign(claimMain, keyManager.paymentPoint(channelKeyPath), remotePerCommitmentPoint, TxOwner.Local, commitments.commitmentFormat)
Transactions.addSigs(claimMain, localPubkey, sig)
})
}
case _: AnchorOutputsCommitmentFormat => withTxGenerationLog("remote-main-delayed") {
Transactions.makeClaimRemoteDelayedOutputTx(tx, commitments.localParams.dustLimit, localPaymentPoint, commitments.localParams.defaultFinalScriptPubKey, feeratePerKwMain).map(claimMain => {
val sig = keyManager.sign(claimMain, keyManager.paymentPoint(channelKeyPath), TxOwner.Local, commitments.commitmentFormat)
Transactions.addSigs(claimMain, sig)
})
commitments.commitmentFormat match {
case DefaultCommitmentFormat => withTxGenerationLog("remote-main") {
Transactions.makeClaimP2WPKHOutputTx(tx, commitments.localParams.dustLimit, localPubkey, commitments.localParams.defaultFinalScriptPubKey, feeratePerKwMain).map(claimMain => {
val sig = keyManager.sign(claimMain, keyManager.paymentPoint(channelKeyPath), remotePerCommitmentPoint, TxOwner.Local, commitments.commitmentFormat)
Transactions.addSigs(claimMain, localPubkey, sig)
})
}
case _: AnchorOutputsCommitmentFormat => withTxGenerationLog("remote-main-delayed") {
Transactions.makeClaimRemoteDelayedOutputTx(tx, commitments.localParams.dustLimit, localPaymentPoint, commitments.localParams.defaultFinalScriptPubKey, feeratePerKwMain).map(claimMain => {
val sig = keyManager.sign(claimMain, keyManager.paymentPoint(channelKeyPath), TxOwner.Local, commitments.commitmentFormat)
Transactions.addSigs(claimMain, sig)
})
}
}
}
RemoteCommitPublished(
commitTx = tx,
claimMainOutputTx = mainTx,
claimHtlcTxs = Map.empty,
claimAnchorTxs = Nil,
irrevocablySpent = Map.empty
)
}
/**