Skip to content

Commit

Permalink
Update InteractiveTxBuilder to send and receive htlcTxsAndRemoteSigs …
Browse files Browse the repository at this point in the history
…needed for 2nd stage claim-htlc-timeout txs
  • Loading branch information
remyers committed Sep 12, 2023
1 parent 8f8b39d commit 81a4814
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,7 @@ case class Commitment(fundingTxIndex: Long,
(copy(nextRemoteCommit_opt = Some(nextRemoteCommit)), commitSig)
}

def receiveCommit(keyManager: ChannelKeyManager, params: ChannelParams, changes: CommitmentChanges, localPerCommitmentPoint: PublicKey, commit: CommitSig)(implicit log: LoggingAdapter): Either[ChannelException, Commitment] = {
def receiveCommit(keyManager: ChannelKeyManager, params: ChannelParams, changes: CommitmentChanges, localPerCommitmentPoint: PublicKey, commit: CommitSig, isSplice: Boolean = false)(implicit log: LoggingAdapter): Either[ChannelException, Commitment] = {
// they sent us a signature for *their* view of *our* next commit tx
// so in terms of rev.hashes and indexes we have:
// ourCommit.index -> our current revocation hash, which is about to become our old revocation hash
Expand All @@ -615,9 +615,10 @@ case class Commitment(fundingTxIndex: Long,
// ourCommit.index + 2 -> which is about to become our next revocation hash
// we will reply to this sig with our old revocation hash preimage (at index) and our next revocation hash (at index + 1)
// and will increment our index
val localCommitIndex = if (isSplice) localCommit.index else localCommit.index + 1
val spec = CommitmentSpec.reduce(localCommit.spec, changes.localChanges.acked, changes.remoteChanges.proposed)
val (localCommitTx, htlcTxs) = Commitment.makeLocalTxs(keyManager, params.channelConfig, params.channelFeatures, localCommit.index + 1, params.localParams, params.remoteParams, fundingTxIndex, remoteFundingPubKey, commitInput, localPerCommitmentPoint, spec)
log.info(s"built local commit number=${localCommit.index + 1} toLocalMsat=${spec.toLocal.toLong} toRemoteMsat=${spec.toRemote.toLong} htlc_in={} htlc_out={} feeratePerKw=${spec.commitTxFeerate} txid=${localCommitTx.tx.txid} fundingTxId=$fundingTxId", spec.htlcs.collect(DirectedHtlc.incoming).map(_.id).mkString(","), spec.htlcs.collect(DirectedHtlc.outgoing).map(_.id).mkString(","))
val (localCommitTx, htlcTxs) = Commitment.makeLocalTxs(keyManager, params.channelConfig, params.channelFeatures, localCommitIndex, params.localParams, params.remoteParams, fundingTxIndex, remoteFundingPubKey, commitInput, localPerCommitmentPoint, spec)
log.info(s"built local commit number=$localCommitIndex toLocalMsat=${spec.toLocal.toLong} toRemoteMsat=${spec.toRemote.toLong} htlc_in={} htlc_out={} feeratePerKw=${spec.commitTxFeerate} txid=${localCommitTx.tx.txid} fundingTxId=$fundingTxId", spec.htlcs.collect(DirectedHtlc.incoming).map(_.id).mkString(","), spec.htlcs.collect(DirectedHtlc.outgoing).map(_.id).mkString(","))
if (!checkSig(localCommitTx, commit.signature, remoteFundingPubKey, TxOwner.Remote, params.commitmentFormat)) {
return Left(InvalidCommitmentSignature(params.channelId, localCommitTx.tx.txid))
}
Expand All @@ -634,7 +635,7 @@ case class Commitment(fundingTxIndex: Long,
HtlcTxAndRemoteSig(htlcTx, remoteSig)
}
// update our commitment data
val localCommit1 = LocalCommit(localCommit.index + 1, spec, CommitTxAndRemoteSig(localCommitTx, commit.signature), htlcTxsAndRemoteSigs)
val localCommit1 = LocalCommit(localCommitIndex, spec, CommitTxAndRemoteSig(localCommitTx, commit.signature), htlcTxsAndRemoteSigs)
Right(copy(localCommit = localCommit1))
}

Expand Down
10 changes: 5 additions & 5 deletions eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ object Helpers {
commitTxFeerate: FeeratePerKw,
fundingTxHash: ByteVector32, fundingTxOutputIndex: Int,
remoteFundingPubKey: PublicKey,
remoteFirstPerCommitmentPoint: PublicKey): Either[ChannelException, (CommitmentSpec, CommitTx, CommitmentSpec, CommitTx)] =
remoteFirstPerCommitmentPoint: PublicKey): Either[ChannelException, (CommitmentSpec, CommitTx, CommitmentSpec, CommitTx, Seq[HtlcTx])] =
makeCommitTxs(keyManager, params,
fundingAmount = localFundingAmount + remoteFundingAmount,
toLocal = localFundingAmount.toMilliSatoshi - localPushAmount + remotePushAmount,
Expand All @@ -392,7 +392,7 @@ object Helpers {
fundingTxHash: ByteVector32, fundingTxOutputIndex: Int,
remoteFundingPubKey: PublicKey,
remotePerCommitmentPoint: PublicKey,
commitmentIndex: Long): Either[ChannelException, (CommitmentSpec, CommitTx, CommitmentSpec, CommitTx)] = {
commitmentIndex: Long): Either[ChannelException, (CommitmentSpec, CommitTx, CommitmentSpec, CommitTx, Seq[HtlcTx])] = {
import params._
val localSpec = CommitmentSpec(localHtlcs, commitTxFeerate, toLocal = toLocal, toRemote = toRemote)
val remoteSpec = CommitmentSpec(localHtlcs.map(_.opposite), commitTxFeerate, toLocal = toRemote, toRemote = toLocal)
Expand All @@ -414,9 +414,9 @@ object Helpers {
val commitmentInput = makeFundingInputInfo(fundingTxHash, fundingTxOutputIndex, fundingAmount, fundingPubKey.publicKey, remoteFundingPubKey)
val localPerCommitmentPoint = keyManager.commitmentPoint(channelKeyPath, commitmentIndex)
val (localCommitTx, _) = Commitment.makeLocalTxs(keyManager, channelConfig, channelFeatures, commitmentIndex, localParams, remoteParams, fundingTxIndex, remoteFundingPubKey, commitmentInput, localPerCommitmentPoint, localSpec)
val (remoteCommitTx, _) = Commitment.makeRemoteTxs(keyManager, channelConfig, channelFeatures, commitmentIndex, localParams, remoteParams, fundingTxIndex, remoteFundingPubKey, commitmentInput, remotePerCommitmentPoint, remoteSpec)

Right(localSpec, localCommitTx, remoteSpec, remoteCommitTx)
val (remoteCommitTx, htlcTxs) = Commitment.makeRemoteTxs(keyManager, channelConfig, channelFeatures, commitmentIndex, localParams, remoteParams, fundingTxIndex, remoteFundingPubKey, commitmentInput, remotePerCommitmentPoint, remoteSpec)
val sortedHtlcTxs = htlcTxs.sortBy(_.input.outPoint.index)
Right(localSpec, localCommitTx, remoteSpec, remoteCommitTx, sortedHtlcTxs)
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers {
// let's create the first commitment tx that spends the yet uncommitted funding tx
Funding.makeFirstCommitTxs(keyManager, params, localFundingAmount = fundingAmount, remoteFundingAmount = 0 sat, localPushAmount = pushMsat, remotePushAmount = 0 msat, commitTxFeerate, fundingTx.hash, fundingTxOutputIndex, remoteFundingPubKey = remoteFundingPubKey, remoteFirstPerCommitmentPoint = remoteFirstPerCommitmentPoint) match {
case Left(ex) => handleLocalError(ex, d, None)
case Right((localSpec, localCommitTx, remoteSpec, remoteCommitTx)) =>
case Right((localSpec, localCommitTx, remoteSpec, remoteCommitTx, _)) =>
require(fundingTx.txOut(fundingTxOutputIndex).publicKeyScript == localCommitTx.input.txOut.publicKeyScript, s"pubkey script mismatch!")
val localSigOfRemoteTx = keyManager.sign(remoteCommitTx, keyManager.fundingPublicKey(params.localParams.fundingKeyPath, fundingTxIndex = 0), TxOwner.Remote, params.channelFeatures.commitmentFormat)
// signature of their initial commitment tx that pays remote pushMsat
Expand Down Expand Up @@ -261,7 +261,7 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers {
// they fund the channel with their funding tx, so the money is theirs (but we are paid pushMsat)
Funding.makeFirstCommitTxs(keyManager, params, localFundingAmount = 0 sat, remoteFundingAmount = fundingAmount, localPushAmount = 0 msat, remotePushAmount = pushMsat, commitTxFeerate, fundingTxHash, fundingTxOutputIndex, remoteFundingPubKey = remoteFundingPubKey, remoteFirstPerCommitmentPoint = remoteFirstPerCommitmentPoint) match {
case Left(ex) => handleLocalError(ex, d, None)
case Right((localSpec, localCommitTx, remoteSpec, remoteCommitTx)) =>
case Right((localSpec, localCommitTx, remoteSpec, remoteCommitTx, _)) =>
// check remote signature validity
val fundingPubKey = keyManager.fundingPublicKey(params.localParams.fundingKeyPath, fundingTxIndex = 0)
val localSigOfLocalTx = keyManager.sign(localCommitTx, fundingPubKey, TxOwner.Local, params.channelFeatures.commitmentFormat)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -741,11 +741,16 @@ private class InteractiveTxBuilder(replyTo: ActorRef[InteractiveTxBuilder.Respon
case Left(cause) =>
replyTo ! RemoteFailure(cause)
unlockAndStop(completeTx)
case Right((localSpec, localCommitTx, remoteSpec, remoteCommitTx)) =>
case Right((localSpec, localCommitTx, remoteSpec, remoteCommitTx, sortedHtlcTxs)) =>
require(fundingTx.txOut(fundingOutputIndex).publicKeyScript == localCommitTx.input.txOut.publicKeyScript, "pubkey script mismatch!")
val fundingPubKey = keyManager.fundingPublicKey(channelParams.localParams.fundingKeyPath, purpose.fundingTxIndex)
val localSigOfRemoteTx = keyManager.sign(remoteCommitTx, fundingPubKey, TxOwner.Remote, channelParams.channelFeatures.commitmentFormat)
val localCommitSig = CommitSig(fundingParams.channelId, localSigOfRemoteTx, Nil)
val localPerCommitmentPoint = keyManager.htlcPoint(keyManager.keyPath(channelParams.localParams, channelParams.channelConfig))
val htlcSignatures = fundingParams.sharedInput_opt match {
case Some(_: Multisig2of2Input) => sortedHtlcTxs.map(keyManager.sign(_, localPerCommitmentPoint, purpose.remotePerCommitmentPoint, TxOwner.Remote, channelParams.commitmentFormat)).toList
case _ => Nil
}
val localCommitSig = CommitSig(fundingParams.channelId, localSigOfRemoteTx, htlcSignatures)
val localCommit = UnsignedLocalCommit(purpose.localCommitIndex, localSpec, localCommitTx, htlcTxs = Nil)
val remoteCommit = RemoteCommit(purpose.remoteCommitIndex, remoteSpec, remoteCommitTx.tx.txid, purpose.remotePerCommitmentPoint)
signFundingTx(completeTx, localCommitSig, localCommit, remoteCommit)
Expand Down Expand Up @@ -918,12 +923,19 @@ object InteractiveTxSigningSession {
case Failure(_) => Left(InvalidCommitmentSignature(fundingParams.channelId, signedLocalCommitTx.tx.txid))
case Success(_) =>
val signedLocalCommit = LocalCommit(unsignedLocalCommit.index, unsignedLocalCommit.spec, CommitTxAndRemoteSig(unsignedLocalCommit.commitTx, remoteCommitSig.signature), htlcTxsAndRemoteSigs = Nil)
val fundingStatus = LocalFundingStatus.DualFundedUnconfirmedFundingTx(fundingTx, nodeParams.currentBlockHeight, fundingParams)
val commitment = Commitment(fundingTxIndex, fundingParams.remoteFundingPubKey, fundingStatus, RemoteFundingStatus.NotLocked, signedLocalCommit, remoteCommit, None)
val channelKeyPath = nodeParams.channelKeyManager.keyPath(channelParams.localParams, channelParams.channelConfig)
val localPerCommitmentPoint = nodeParams.channelKeyManager.commitmentPoint(channelKeyPath, signedLocalCommit.index)
val commitment1 = commitment.receiveCommit(nodeParams.channelKeyManager, channelParams, CommitmentChanges.init(), localPerCommitmentPoint, remoteCommitSig, isSplice = true) match {
case Left(f) => return Left(f)
case Right(signedLocalCommit) => signedLocalCommit
}
if (shouldSignFirst(channelParams, fundingTx.tx)) {
val fundingStatus = LocalFundingStatus.DualFundedUnconfirmedFundingTx(fundingTx, nodeParams.currentBlockHeight, fundingParams)
val commitment = Commitment(fundingTxIndex, fundingParams.remoteFundingPubKey, fundingStatus, RemoteFundingStatus.NotLocked, signedLocalCommit, remoteCommit, None)
Right(SendingSigs(fundingStatus, commitment, fundingTx.localSigs))
// update our commitment data
Right(SendingSigs(fundingStatus, commitment1, fundingTx.localSigs))
} else {
Right(this.copy(localCommit = Right(signedLocalCommit)))
Right(this.copy(localCommit = Right(commitment1.localCommit)))
}
}
case Right(_) =>
Expand Down

0 comments on commit 81a4814

Please sign in to comment.