Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey
import fr.acinq.bitcoin.scalacompat.{ByteVector64, DeterministicWallet, OutPoint, Satoshi, SatoshiLong, Script, ScriptWitness, Transaction, TxIn, TxOut, addressToPublicKeyScript}
import fr.acinq.eclair.blockchain.fee.FeeratePerKw
import fr.acinq.eclair.transactions.Scripts.multiSig2of2
import fr.acinq.eclair.transactions.Transactions._
import fr.acinq.eclair.transactions.{Scripts, Transactions}
import fr.acinq.eclair.transactions.Transactions.{DefaultCommitmentFormat, InputInfo, PlaceHolderPubKey, PlaceHolderSig, TxOwner}
import scodec.bits.ByteVector

import scala.concurrent.Future
Expand Down Expand Up @@ -42,10 +42,10 @@ trait SpendFromChannelAddress {
outPoint = unsignedTx.txIn.head.outPoint
inputTx <- appKit.wallet.getTransaction(outPoint.txid)
localFundingPubkey = appKit.nodeParams.channelKeyManager.fundingPublicKey(fundingKeyPath, fundingTxIndex)
fundingRedeemScript = multiSig2of2(localFundingPubkey.publicKey, remoteFundingPubkey)
inputInfo = InputInfo(outPoint, inputTx.txOut(outPoint.index.toInt), fundingRedeemScript)
redeemInfo = RedeemInfo.SegwitV0(multiSig2of2(localFundingPubkey.publicKey, remoteFundingPubkey))
inputInfo = InputInfo(outPoint, inputTx.txOut(outPoint.index.toInt))
localSig = appKit.nodeParams.channelKeyManager.sign(
Transactions.SpliceTx(inputInfo, unsignedTx), // classify as splice, doesn't really matter
Transactions.SpliceTx(inputInfo, redeemInfo, unsignedTx), // classify as splice, doesn't really matter
localFundingPubkey,
TxOwner.Local, // unused
DefaultCommitmentFormat, // unused
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ final case class RES_ADD_FAILED[+T <: ChannelException](c: CMD_ADD_HTLC, t: T, c
sealed trait HtlcResult
object HtlcResult {
sealed trait Fulfill extends HtlcResult { def paymentPreimage: ByteVector32 }
case class RemoteFulfill(fulfill: UpdateFulfillHtlc) extends Fulfill { override val paymentPreimage = fulfill.paymentPreimage }
case class RemoteFulfill(fulfill: UpdateFulfillHtlc) extends Fulfill { override val paymentPreimage: ByteVector32 = fulfill.paymentPreimage }
case class OnChainFulfill(paymentPreimage: ByteVector32) extends Fulfill
sealed trait Fail extends HtlcResult
case class RemoteFail(fail: UpdateFailHtlc) extends Fail
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package fr.acinq.eclair.channel
import akka.event.LoggingAdapter
import fr.acinq.bitcoin.crypto.musig2.IndividualNonce
import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey}
import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, Crypto, Satoshi, SatoshiLong, Script, Transaction, TxId}
import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, Crypto, Satoshi, SatoshiLong, Transaction, TxId}
import fr.acinq.eclair.blockchain.fee.{FeeratePerByte, FeeratePerKw, FeeratesPerKw, OnChainFeeConf}
import fr.acinq.eclair.channel.Helpers.Closing
import fr.acinq.eclair.channel.Monitoring.{Metrics, Tags}
Expand Down Expand Up @@ -192,10 +192,10 @@ case class LocalCommit(index: Long, spec: CommitmentSpec, commitTxAndRemoteSig:

object LocalCommit {
def fromCommitSig(keyManager: ChannelKeyManager, params: ChannelParams, fundingTxId: TxId,
fundingTxIndex: Long, remoteFundingPubKey: PublicKey, commitInput: InputInfo,
fundingTxIndex: Long, remoteFundingPubKey: PublicKey, commitInput: InputInfo, redeemInfo: RedeemInfo.TaprootKeyPathOrSegwitV0,
commit: CommitSig, localCommitIndex: Long, spec: CommitmentSpec, localPerCommitmentPoint: PublicKey): Either[ChannelException, LocalCommit] = {
val (localCommitTx, htlcTxs) = Commitment.makeLocalTxs(keyManager, params.channelConfig, params.channelFeatures, localCommitIndex, params.localParams, params.remoteParams, fundingTxIndex, remoteFundingPubKey, commitInput, localPerCommitmentPoint, spec)
if (!localCommitTx.checkSig(commit.signature, remoteFundingPubKey, TxOwner.Remote, params.commitmentFormat)) {
val (localCommitTx, htlcTxs) = Commitment.makeLocalTxs(keyManager, params.channelConfig, params.channelFeatures, localCommitIndex, params.localParams, params.remoteParams, fundingTxIndex, remoteFundingPubKey, commitInput, redeemInfo, localPerCommitmentPoint, spec)
if (!localCommitTx.checkSig(commit.signature, remoteFundingPubKey, TxOwner.Remote, params.commitmentFormat, extraUtxos = Map.empty)) {
return Left(InvalidCommitmentSignature(params.channelId, fundingTxId, fundingTxIndex, localCommitTx.tx))
}
val sortedHtlcTxs = htlcTxs.sortBy(_.input.outPoint.index)
Expand All @@ -205,7 +205,7 @@ object LocalCommit {
val remoteHtlcPubkey = Generators.derivePubKey(params.remoteParams.htlcBasepoint, localPerCommitmentPoint)
val htlcTxsAndRemoteSigs = sortedHtlcTxs.zip(commit.htlcSignatures).toList.map {
case (htlcTx: HtlcTx, remoteSig) =>
if (!htlcTx.checkSig(remoteSig, remoteHtlcPubkey, TxOwner.Remote, params.commitmentFormat)) {
if (!htlcTx.checkSig(remoteSig, remoteHtlcPubkey, TxOwner.Remote, params.commitmentFormat, extraUtxos = Map.empty)) {
return Left(InvalidHtlcSignature(params.channelId, htlcTx.tx.txid))
}
HtlcTxAndRemoteSig(htlcTx, remoteSig)
Expand All @@ -216,8 +216,8 @@ object LocalCommit {

/** The remote commitment maps to a commitment transaction that only our peer can sign and broadcast. */
case class RemoteCommit(index: Long, spec: CommitmentSpec, txid: TxId, remotePerCommitmentPoint: PublicKey) {
def sign(keyManager: ChannelKeyManager, params: ChannelParams, fundingTxIndex: Long, remoteFundingPubKey: PublicKey, commitInput: InputInfo): CommitSig = {
val (remoteCommitTx, htlcTxs) = Commitment.makeRemoteTxs(keyManager, params.channelConfig, params.channelFeatures, index, params.localParams, params.remoteParams, fundingTxIndex, remoteFundingPubKey, commitInput, remotePerCommitmentPoint, spec)
def sign(keyManager: ChannelKeyManager, params: ChannelParams, fundingTxIndex: Long, remoteFundingPubKey: PublicKey, commitInput: InputInfo, redeemInfo: RedeemInfo.TaprootKeyPathOrSegwitV0): CommitSig = {
val (remoteCommitTx, htlcTxs) = Commitment.makeRemoteTxs(keyManager, params.channelConfig, params.channelFeatures, index, params.localParams, params.remoteParams, fundingTxIndex, remoteFundingPubKey, commitInput, redeemInfo, remotePerCommitmentPoint, spec)
val sig = keyManager.sign(remoteCommitTx, keyManager.fundingPublicKey(params.localParams.fundingKeyPath, fundingTxIndex), TxOwner.Remote, params.commitmentFormat, Map.empty)
val channelKeyPath = keyManager.keyPath(params.localParams, params.channelConfig)
val sortedHtlcTxs = htlcTxs.sortBy(_.input.outPoint.index)
Expand Down Expand Up @@ -246,6 +246,7 @@ case class Commitment(fundingTxIndex: Long,
localFundingStatus: LocalFundingStatus, remoteFundingStatus: RemoteFundingStatus,
localCommit: LocalCommit, remoteCommit: RemoteCommit, nextRemoteCommit_opt: Option[NextRemoteCommit]) {
val commitInput: InputInfo = localCommit.commitTxAndRemoteSig.commitTx.input
val redeemInfo: RedeemInfo.TaprootKeyPathOrSegwitV0 = localCommit.commitTxAndRemoteSig.commitTx.redeemInfo
val fundingTxId: TxId = commitInput.outPoint.txid
val capacity: Satoshi = commitInput.txOut.amount
/** Once the funding transaction is confirmed, short_channel_id matching this transaction. */
Expand Down Expand Up @@ -621,7 +622,7 @@ case class Commitment(fundingTxIndex: Long,
def sendCommit(keyManager: ChannelKeyManager, params: ChannelParams, changes: CommitmentChanges, remoteNextPerCommitmentPoint: PublicKey, batchSize: Int)(implicit log: LoggingAdapter): (Commitment, CommitSig) = {
// remote commitment will include all local proposed changes + remote acked changes
val spec = CommitmentSpec.reduce(remoteCommit.spec, changes.remoteChanges.acked, changes.localChanges.proposed)
val (remoteCommitTx, htlcTxs) = Commitment.makeRemoteTxs(keyManager, params.channelConfig, params.channelFeatures, remoteCommit.index + 1, params.localParams, params.remoteParams, fundingTxIndex, remoteFundingPubKey, commitInput, remoteNextPerCommitmentPoint, spec)
val (remoteCommitTx, htlcTxs) = Commitment.makeRemoteTxs(keyManager, params.channelConfig, params.channelFeatures, remoteCommit.index + 1, params.localParams, params.remoteParams, fundingTxIndex, remoteFundingPubKey, commitInput, redeemInfo, remoteNextPerCommitmentPoint, spec)
val sig = keyManager.sign(remoteCommitTx, keyManager.fundingPublicKey(params.localParams.fundingKeyPath, fundingTxIndex), TxOwner.Remote, params.commitmentFormat, Map.empty)

val sortedHtlcTxs: Seq[TransactionWithInputInfo] = htlcTxs.sortBy(_.input.outPoint.index)
Expand Down Expand Up @@ -650,7 +651,7 @@ case class Commitment(fundingTxIndex: Long,
// and will increment our index
val localCommitIndex = localCommit.index + 1
val spec = CommitmentSpec.reduce(localCommit.spec, changes.localChanges.acked, changes.remoteChanges.proposed)
LocalCommit.fromCommitSig(keyManager, params, fundingTxId, fundingTxIndex, remoteFundingPubKey, commitInput, commit, localCommitIndex, spec, localPerCommitmentPoint).map { localCommit1 =>
LocalCommit.fromCommitSig(keyManager, params, fundingTxId, fundingTxIndex, remoteFundingPubKey, commitInput, redeemInfo, commit, localCommitIndex, spec, localPerCommitmentPoint).map { localCommit1 =>
log.info(s"built local commit number=$localCommitIndex toLocalMsat=${spec.toLocal.toLong} toRemoteMsat=${spec.toRemote.toLong} htlc_in={} htlc_out={} feeratePerKw=${spec.commitTxFeerate} txid=${localCommit1.commitTxAndRemoteSig.commitTx.tx.txid} fundingTxId=$fundingTxId", spec.htlcs.collect(DirectedHtlc.incoming).map(_.id).mkString(","), spec.htlcs.collect(DirectedHtlc.outgoing).map(_.id).mkString(","))
copy(localCommit = localCommit1)
}
Expand Down Expand Up @@ -679,6 +680,7 @@ object Commitment {
fundingTxIndex: Long,
remoteFundingPubKey: PublicKey,
commitmentInput: InputInfo,
redeemInfo: RedeemInfo.TaprootKeyPathOrSegwitV0,
localPerCommitmentPoint: PublicKey,
spec: CommitmentSpec): (CommitTx, Seq[HtlcTx]) = {
val channelKeyPath = keyManager.keyPath(localParams, channelConfig)
Expand All @@ -694,7 +696,7 @@ object Commitment {
val localRevocationPubkey = Generators.revocationPubKey(remoteParams.revocationBasepoint, localPerCommitmentPoint)
val localPaymentBasepoint = localParams.walletStaticPaymentBasepoint.getOrElse(keyManager.paymentPoint(channelKeyPath).publicKey)
val outputs = makeCommitTxOutputs(localParams.paysCommitTxFees, localParams.dustLimit, localRevocationPubkey, remoteParams.toSelfDelay, localDelayedPaymentPubkey, remotePaymentPubkey, localHtlcPubkey, remoteHtlcPubkey, localFundingPubkey, remoteFundingPubKey, spec, channelFeatures.commitmentFormat)
val commitTx = makeCommitTx(commitmentInput, commitTxNumber, localPaymentBasepoint, remoteParams.paymentBasepoint, localParams.isChannelOpener, outputs)
val commitTx = makeCommitTx(commitmentInput, redeemInfo, commitTxNumber, localPaymentBasepoint, remoteParams.paymentBasepoint, localParams.isChannelOpener, outputs)
val htlcTxs = makeHtlcTxs(commitTx.tx, localParams.dustLimit, localRevocationPubkey, remoteParams.toSelfDelay, localDelayedPaymentPubkey, spec.htlcTxFeerate(channelFeatures.commitmentFormat), outputs, channelFeatures.commitmentFormat)
(commitTx, htlcTxs)
}
Expand All @@ -708,6 +710,7 @@ object Commitment {
fundingTxIndex: Long,
remoteFundingPubKey: PublicKey,
commitmentInput: InputInfo,
redeemInfo: RedeemInfo.TaprootKeyPathOrSegwitV0,
remotePerCommitmentPoint: PublicKey,
spec: CommitmentSpec): (CommitTx, Seq[HtlcTx]) = {
val channelKeyPath = keyManager.keyPath(localParams, channelConfig)
Expand All @@ -723,7 +726,7 @@ object Commitment {
val remoteHtlcPubkey = Generators.derivePubKey(remoteParams.htlcBasepoint, remotePerCommitmentPoint)
val remoteRevocationPubkey = Generators.revocationPubKey(keyManager.revocationPoint(channelKeyPath).publicKey, remotePerCommitmentPoint)
val outputs = makeCommitTxOutputs(!localParams.paysCommitTxFees, remoteParams.dustLimit, remoteRevocationPubkey, localParams.toSelfDelay, remoteDelayedPaymentPubkey, localPaymentPubkey, remoteHtlcPubkey, localHtlcPubkey, remoteFundingPubKey, localFundingPubkey, spec, channelFeatures.commitmentFormat)
val commitTx = makeCommitTx(commitmentInput, commitTxNumber, remoteParams.paymentBasepoint, localPaymentBasepoint, !localParams.isChannelOpener, outputs)
val commitTx = makeCommitTx(commitmentInput, redeemInfo, commitTxNumber, remoteParams.paymentBasepoint, localPaymentBasepoint, !localParams.isChannelOpener, outputs)
val htlcTxs = makeHtlcTxs(commitTx.tx, remoteParams.dustLimit, remoteRevocationPubkey, localParams.toSelfDelay, remoteDelayedPaymentPubkey, spec.htlcTxFeerate(channelFeatures.commitmentFormat), outputs, channelFeatures.commitmentFormat)
(commitTx, htlcTxs)
}
Expand Down Expand Up @@ -751,6 +754,7 @@ case class FullCommitment(params: ChannelParams, changes: CommitmentChanges,
val localParams = params.localParams
val remoteParams = params.remoteParams
val commitInput = localCommit.commitTxAndRemoteSig.commitTx.input
val redeemInfo = localCommit.commitTxAndRemoteSig.commitTx.redeemInfo
val fundingTxId = commitInput.outPoint.txid
val capacity = commitInput.txOut.amount
val commitment = Commitment(fundingTxIndex, firstRemoteCommitIndex, remoteFundingPubKey, localFundingStatus, remoteFundingStatus, localCommit, remoteCommit, nextRemoteCommit_opt)
Expand Down Expand Up @@ -1154,11 +1158,8 @@ case class Commitments(params: ChannelParams,
active.forall { commitment =>
val localFundingKey = keyManager.fundingPublicKey(params.localParams.fundingKeyPath, commitment.fundingTxIndex).publicKey
val remoteFundingKey = commitment.remoteFundingPubKey
val fundingScript = Script.write(Scripts.multiSig2of2(localFundingKey, remoteFundingKey))
commitment.commitInput match {
case InputInfo.SegwitInput(_, _, redeemScript) => redeemScript == fundingScript
case _: InputInfo.TaprootInput => false
}
val fundingScript = Helpers.Funding.makeFundingPubKeyScript(localFundingKey, remoteFundingKey, params.commitmentFormat)
commitment.commitInput.txOut.publicKeyScript == fundingScript
}
}

Expand Down
Loading