@@ -875,8 +875,14 @@ object Helpers {
875875
876876 object LocalClose {
877877
878+ /** Transactions spending outputs of our commitment transaction. */
879+ case class SecondStageTransactions (mainDelayedTx_opt : Option [ClaimLocalDelayedOutputTx ], anchorTx_opt : Option [ClaimAnchorOutputTx ], htlcTxs : Seq [HtlcTx ])
880+
881+ /** Transactions spending outputs of our HTLC transactions. */
882+ case class ThirdStageTransactions (htlcDelayedTxs : Seq [HtlcDelayedTx ])
883+
878884 /** Claim all the outputs that belong to us in our local commitment transaction. */
879- def claimCommitTxOutputs (channelKeys : ChannelKeys , commitment : FullCommitment , commitTx : Transaction , feerates : FeeratesPerKw , onChainFeeConf : OnChainFeeConf , finalScriptPubKey : ByteVector )(implicit log : LoggingAdapter ): LocalCommitPublished = {
885+ def claimCommitTxOutputs (channelKeys : ChannelKeys , commitment : FullCommitment , commitTx : Transaction , feerates : FeeratesPerKw , onChainFeeConf : OnChainFeeConf , finalScriptPubKey : ByteVector )(implicit log : LoggingAdapter ): ( LocalCommitPublished , SecondStageTransactions ) = {
880886 require(commitment.localCommit.commitTxAndRemoteSig.commitTx.tx.txid == commitTx.txid, " txid mismatch, provided tx is not the current local commit tx" )
881887 val fundingKey = channelKeys.fundingKey(commitment.fundingTxIndex)
882888 val commitmentKeys = commitment.localKeys(channelKeys)
@@ -891,14 +897,16 @@ object Helpers {
891897 } else {
892898 None
893899 }
894- LocalCommitPublished (
900+ val lcp = LocalCommitPublished (
895901 commitTx = commitTx,
896902 claimMainDelayedOutputTx = mainDelayedTx_opt,
897903 htlcTxs = htlcTxs,
898904 claimHtlcDelayedTxs = Nil , // we will claim these once the htlc txs are confirmed
899905 claimAnchorTxs = anchorTx_opt.toList,
900906 irrevocablySpent = Map .empty
901907 )
908+ val txs = SecondStageTransactions (mainDelayedTx_opt, anchorTx_opt, htlcTxs.values.flatten.toSeq)
909+ (lcp, txs)
902910 }
903911
904912 def claimAnchor (fundingKey : PrivateKey , commitKeys : LocalCommitmentKeys , commitTx : Transaction , commitmentFormat : CommitmentFormat )(implicit log : LoggingAdapter ): Option [ClaimAnchorOutputTx ] = {
@@ -1002,28 +1010,31 @@ object Helpers {
10021010 * NB: with anchor outputs, it's possible to have transactions that spend *many* HTLC outputs at once, but we're not
10031011 * doing that because it introduces a lot of subtle edge cases.
10041012 */
1005- def claimHtlcDelayedOutput (localCommitPublished : LocalCommitPublished , channelKeys : ChannelKeys , commitment : FullCommitment , tx : Transaction , feerates : FeeratesPerKw , onChainFeeConf : OnChainFeeConf , finalScriptPubKey : ByteVector )(implicit log : LoggingAdapter ): (LocalCommitPublished , Option [ HtlcDelayedTx ] ) = {
1013+ def claimHtlcDelayedOutput (localCommitPublished : LocalCommitPublished , channelKeys : ChannelKeys , commitment : FullCommitment , tx : Transaction , feerates : FeeratesPerKw , onChainFeeConf : OnChainFeeConf , finalScriptPubKey : ByteVector )(implicit log : LoggingAdapter ): (LocalCommitPublished , ThirdStageTransactions ) = {
10061014 if (tx.txIn.exists(txIn => localCommitPublished.htlcTxs.contains(txIn.outPoint))) {
1007- val feeratePerKwDelayed = onChainFeeConf.getClosingFeerate(feerates)
1015+ val feerateDelayed = onChainFeeConf.getClosingFeerate(feerates)
10081016 val commitKeys = commitment.localKeys(channelKeys)
10091017 // Note that this will return None if the transaction wasn't one of our HTLC transactions, which may happen
10101018 // if our peer was able to claim the HTLC output before us (race condition between success and timeout).
10111019 val htlcDelayedTx_opt = withTxGenerationLog(" htlc-delayed" ) {
1012- HtlcDelayedTx .createSignedTx(commitKeys, tx, commitment.localParams.dustLimit, commitment.remoteParams.toSelfDelay, finalScriptPubKey, feeratePerKwDelayed , commitment.params.commitmentFormat)
1020+ HtlcDelayedTx .createSignedTx(commitKeys, tx, commitment.localParams.dustLimit, commitment.remoteParams.toSelfDelay, finalScriptPubKey, feerateDelayed , commitment.params.commitmentFormat)
10131021 }
10141022 val localCommitPublished1 = localCommitPublished.copy(claimHtlcDelayedTxs = localCommitPublished.claimHtlcDelayedTxs ++ htlcDelayedTx_opt.toSeq)
1015- (localCommitPublished1, htlcDelayedTx_opt)
1023+ (localCommitPublished1, ThirdStageTransactions ( htlcDelayedTx_opt.toSeq) )
10161024 } else {
1017- (localCommitPublished, None )
1025+ (localCommitPublished, ThirdStageTransactions ( Nil ) )
10181026 }
10191027 }
10201028
10211029 }
10221030
10231031 object RemoteClose {
10241032
1033+ /** Transactions spending outputs of a remote commitment transaction. */
1034+ case class SecondStageTransactions (mainTx_opt : Option [ClaimRemoteCommitMainOutputTx ], anchorTx_opt : Option [ClaimAnchorOutputTx ], htlcTxs : Seq [ClaimHtlcTx ])
1035+
10251036 /** Claim all the outputs that belong to us in the remote commitment transaction (which can be either their current or next commitment). */
1026- def claimCommitTxOutputs (channelKeys : ChannelKeys , commitment : FullCommitment , remoteCommit : RemoteCommit , commitTx : Transaction , feerates : FeeratesPerKw , onChainFeeConf : OnChainFeeConf , finalScriptPubKey : ByteVector )(implicit log : LoggingAdapter ): RemoteCommitPublished = {
1037+ def claimCommitTxOutputs (channelKeys : ChannelKeys , commitment : FullCommitment , remoteCommit : RemoteCommit , commitTx : Transaction , feerates : FeeratesPerKw , onChainFeeConf : OnChainFeeConf , finalScriptPubKey : ByteVector )(implicit log : LoggingAdapter ): ( RemoteCommitPublished , SecondStageTransactions ) = {
10271038 require(remoteCommit.txid == commitTx.txid, " txid mismatch, provided tx is not the current remote commit tx" )
10281039 val fundingKey = channelKeys.fundingKey(commitment.fundingTxIndex)
10291040 val commitKeys = commitment.remoteKeys(channelKeys, remoteCommit.remotePerCommitmentPoint)
@@ -1035,13 +1046,15 @@ object Helpers {
10351046 } else {
10361047 None
10371048 }
1038- RemoteCommitPublished (
1049+ val rcp = RemoteCommitPublished (
10391050 commitTx = commitTx,
10401051 claimMainOutputTx = mainTx_opt,
10411052 claimHtlcTxs = htlcTxs,
10421053 claimAnchorTxs = anchorTx_opt.toList,
10431054 irrevocablySpent = Map .empty
10441055 )
1056+ val txs = SecondStageTransactions (mainTx_opt, anchorTx_opt, htlcTxs.values.flatten.toSeq)
1057+ (rcp, txs)
10451058 }
10461059
10471060 def claimAnchor (fundingKey : PrivateKey , commitKeys : RemoteCommitmentKeys , commitTx : Transaction , commitmentFormat : CommitmentFormat )(implicit log : LoggingAdapter ): Option [ClaimAnchorOutputTx ] = {
@@ -1171,6 +1184,12 @@ object Helpers {
11711184
11721185 object RevokedClose {
11731186
1187+ /** Transactions spending outputs of a revoked remote commitment transactions. */
1188+ case class SecondStageTransactions (mainTx_opt : Option [ClaimRemoteCommitMainOutputTx ], mainPenaltyTx_opt : Option [MainPenaltyTx ], htlcPenaltyTxs : Seq [HtlcPenaltyTx ])
1189+
1190+ /** Transactions spending outputs of confirmed remote HTLC transactions. */
1191+ case class ThirdStageTransactions (htlcDelayedPenaltyTxs : Seq [ClaimHtlcDelayedOutputPenaltyTx ])
1192+
11741193 /**
11751194 * When an unexpected transaction spending the funding tx is detected, we must be in one of the following scenarios:
11761195 *
@@ -1203,7 +1222,7 @@ object Helpers {
12031222 * When a revoked commitment transaction spending the funding tx is detected, we build a set of transactions that
12041223 * will punish our peer by stealing all their funds.
12051224 */
1206- def claimCommitTxOutputs (params : ChannelParams , channelKeys : ChannelKeys , commitTx : Transaction , commitmentNumber : Long , remotePerCommitmentSecret : PrivateKey , db : ChannelsDb , feerates : FeeratesPerKw , onChainFeeConf : OnChainFeeConf , finalScriptPubKey : ByteVector )(implicit log : LoggingAdapter ): RevokedCommitPublished = {
1225+ def claimCommitTxOutputs (params : ChannelParams , channelKeys : ChannelKeys , commitTx : Transaction , commitmentNumber : Long , remotePerCommitmentSecret : PrivateKey , db : ChannelsDb , feerates : FeeratesPerKw , onChainFeeConf : OnChainFeeConf , finalScriptPubKey : ByteVector )(implicit log : LoggingAdapter ): ( RevokedCommitPublished , SecondStageTransactions ) = {
12071226 import params ._
12081227 log.warning(" a revoked commit has been published with commitmentNumber={}" , commitmentNumber)
12091228
@@ -1236,14 +1255,16 @@ object Helpers {
12361255 val htlcPenaltyTxs = HtlcPenaltyTx .createSignedTxs(commitKeys, revocationKey, commitTx, htlcInfos, localParams.dustLimit, finalScriptPubKey, feeratePenalty, commitmentFormat)
12371256 .flatMap(htlcPenaltyTx => withTxGenerationLog(" htlc-penalty" )(htlcPenaltyTx))
12381257
1239- RevokedCommitPublished (
1258+ val rvk = RevokedCommitPublished (
12401259 commitTx = commitTx,
12411260 claimMainOutputTx = mainTx_opt,
12421261 mainPenaltyTx = mainPenaltyTx_opt,
12431262 htlcPenaltyTxs = htlcPenaltyTxs.toList,
12441263 claimHtlcDelayedPenaltyTxs = Nil , // we will generate and spend those if they publish their HtlcSuccessTx or HtlcTimeoutTx
12451264 irrevocablySpent = Map .empty
12461265 )
1266+ val txs = SecondStageTransactions (mainTx_opt, mainPenaltyTx_opt, htlcPenaltyTxs)
1267+ (rvk, txs)
12471268 }
12481269
12491270 /**
@@ -1259,7 +1280,7 @@ object Helpers {
12591280 * NB: when anchor outputs is used, htlc transactions can be aggregated in a single transaction if they share the same
12601281 * lockTime (thanks to the use of sighash_single | sighash_anyonecanpay), so we may need to claim multiple outputs.
12611282 */
1262- def claimHtlcTxOutputs (params : ChannelParams , channelKeys : ChannelKeys , remotePerCommitmentSecrets : ShaChain , revokedCommitPublished : RevokedCommitPublished , htlcTx : Transaction , feerates : FeeratesPerKw , finalScriptPubKey : ByteVector )(implicit log : LoggingAdapter ): (RevokedCommitPublished , Seq [ ClaimHtlcDelayedOutputPenaltyTx ] ) = {
1283+ def claimHtlcTxOutputs (params : ChannelParams , channelKeys : ChannelKeys , remotePerCommitmentSecrets : ShaChain , revokedCommitPublished : RevokedCommitPublished , htlcTx : Transaction , feerates : FeeratesPerKw , finalScriptPubKey : ByteVector )(implicit log : LoggingAdapter ): (RevokedCommitPublished , ThirdStageTransactions ) = {
12631284 // We published HTLC-penalty transactions for every HTLC output: this transaction may be ours, or it may be one
12641285 // of their HTLC transactions that confirmed before our HTLC-penalty transaction. If it is spending an HTLC
12651286 // output, we assume that it's an HTLC transaction published by our peer and try to create penalty transactions
@@ -1284,10 +1305,11 @@ object Helpers {
12841305 }
12851306 })
12861307 val revokedCommitPublished1 = revokedCommitPublished.copy(claimHtlcDelayedPenaltyTxs = revokedCommitPublished.claimHtlcDelayedPenaltyTxs ++ penaltyTxs)
1287- (revokedCommitPublished1, penaltyTxs)
1288- }.getOrElse((revokedCommitPublished, Nil ))
1308+ val txs = ThirdStageTransactions (penaltyTxs)
1309+ (revokedCommitPublished1, txs)
1310+ }.getOrElse((revokedCommitPublished, ThirdStageTransactions (Nil )))
12891311 } else {
1290- (revokedCommitPublished, Nil )
1312+ (revokedCommitPublished, ThirdStageTransactions ( Nil ) )
12911313 }
12921314 }
12931315
@@ -1519,26 +1541,6 @@ object Helpers {
15191541 revokedCommitPublished.copy(irrevocablySpent = revokedCommitPublished.irrevocablySpent ++ relevantOutpoints.map(o => o -> tx).toMap)
15201542 }
15211543
1522- /**
1523- * This helper function tells if some of the utxos consumed by the given transaction have already been irrevocably spent (possibly by this very transaction).
1524- *
1525- * It can be useful to:
1526- * - not attempt to publish this tx when we know this will fail
1527- * - not watch for confirmations if we know the tx is already confirmed
1528- * - not watch the corresponding utxo when we already know the final spending tx
1529- *
1530- * @param tx an arbitrary transaction
1531- * @param irrevocablySpent a map of known spent outpoints
1532- * @return true if we know for sure that the utxos consumed by the tx have already irrevocably been spent, false otherwise
1533- */
1534- def inputsAlreadySpent (tx : Transaction , irrevocablySpent : Map [OutPoint , Transaction ]): Boolean = {
1535- tx.txIn.exists(txIn => irrevocablySpent.contains(txIn.outPoint))
1536- }
1537-
1538- def inputAlreadySpent (input : OutPoint , irrevocablySpent : Map [OutPoint , Transaction ]): Boolean = {
1539- irrevocablySpent.contains(input)
1540- }
1541-
15421544 }
15431545
15441546}
0 commit comments