mirror of
https://github.com/ACINQ/eclair.git
synced 2025-03-13 03:14:26 +01:00
Fixup: SimpleTaprootChannelCommitmentFormat should not be a subtype of AnchorOutputsCommitmentFormat
This commit is contained in:
parent
17908a3690
commit
1c4215fb3c
15 changed files with 126 additions and 115 deletions
|
@ -134,7 +134,7 @@ case class NodeParams(nodeKeyManager: NodeKeyManager,
|
||||||
min = (commitmentFeerate * feerateTolerance.ratioLow).max(minimumFeerate),
|
min = (commitmentFeerate * feerateTolerance.ratioLow).max(minimumFeerate),
|
||||||
max = (commitmentFormat match {
|
max = (commitmentFormat match {
|
||||||
case Transactions.DefaultCommitmentFormat => commitmentFeerate * feerateTolerance.ratioHigh
|
case Transactions.DefaultCommitmentFormat => commitmentFeerate * feerateTolerance.ratioHigh
|
||||||
case _: Transactions.AnchorOutputsCommitmentFormat => (commitmentFeerate * feerateTolerance.ratioHigh).max(feerateTolerance.anchorOutputMaxCommitFeerate)
|
case _: Transactions.AnchorOutputsCommitmentFormat | Transactions.SimpleTaprootChannelCommitmentFormat => (commitmentFeerate * feerateTolerance.ratioHigh).max(feerateTolerance.anchorOutputMaxCommitFeerate)
|
||||||
}).max(minimumFeerate),
|
}).max(minimumFeerate),
|
||||||
)
|
)
|
||||||
RecommendedFeerates(chainHash, fundingFeerate, commitmentFeerate, TlvStream(fundingRange, commitmentRange))
|
RecommendedFeerates(chainHash, fundingFeerate, commitmentFeerate, TlvStream(fundingRange, commitmentRange))
|
||||||
|
|
|
@ -121,7 +121,7 @@ case class OnChainFeeConf(feeTargets: FeeTargets,
|
||||||
|
|
||||||
commitmentFormat match {
|
commitmentFormat match {
|
||||||
case Transactions.DefaultCommitmentFormat => networkFeerate
|
case Transactions.DefaultCommitmentFormat => networkFeerate
|
||||||
case _: Transactions.AnchorOutputsCommitmentFormat =>
|
case _: Transactions.AnchorOutputsCommitmentFormat | Transactions.SimpleTaprootChannelCommitmentFormat =>
|
||||||
val targetFeerate = networkFeerate.min(feerateToleranceFor(remoteNodeId).anchorOutputMaxCommitFeerate)
|
val targetFeerate = networkFeerate.min(feerateToleranceFor(remoteNodeId).anchorOutputMaxCommitFeerate)
|
||||||
// We make sure the feerate is always greater than the propagation threshold.
|
// We make sure the feerate is always greater than the propagation threshold.
|
||||||
targetFeerate.max(networkMinFee * 1.25)
|
targetFeerate.max(networkMinFee * 1.25)
|
||||||
|
|
|
@ -357,17 +357,19 @@ object Helpers {
|
||||||
}
|
}
|
||||||
|
|
||||||
object Funding {
|
object Funding {
|
||||||
def makeFundingPubKeyScript(localFundingKey: PublicKey, remoteFundingKey: PublicKey, commitmentFormat: CommitmentFormat): ByteVector = if (commitmentFormat.useTaproot) {
|
def makeFundingPubKeyScript(localFundingKey: PublicKey, remoteFundingKey: PublicKey, commitmentFormat: CommitmentFormat): ByteVector = commitmentFormat match {
|
||||||
|
case SimpleTaprootChannelCommitmentFormat =>
|
||||||
write(Taproot.musig2FundingScript(localFundingKey, remoteFundingKey))
|
write(Taproot.musig2FundingScript(localFundingKey, remoteFundingKey))
|
||||||
} else {
|
case _ =>
|
||||||
write(pay2wsh(multiSig2of2(localFundingKey, remoteFundingKey)))
|
write(pay2wsh(multiSig2of2(localFundingKey, remoteFundingKey)))
|
||||||
}
|
}
|
||||||
|
|
||||||
def makeFundingInputInfo(fundingTxId: TxId, fundingTxOutputIndex: Int, fundingSatoshis: Satoshi, fundingPubkey1: PublicKey, fundingPubkey2: PublicKey, commitmentFormat: CommitmentFormat): InputInfo = if (commitmentFormat.useTaproot) {
|
def makeFundingInputInfo(fundingTxId: TxId, fundingTxOutputIndex: Int, fundingSatoshis: Satoshi, fundingPubkey1: PublicKey, fundingPubkey2: PublicKey, commitmentFormat: CommitmentFormat): InputInfo = commitmentFormat match {
|
||||||
|
case SimpleTaprootChannelCommitmentFormat =>
|
||||||
val fundingScript = Taproot.musig2FundingScript(fundingPubkey1, fundingPubkey2)
|
val fundingScript = Taproot.musig2FundingScript(fundingPubkey1, fundingPubkey2)
|
||||||
val fundingTxOut = TxOut(fundingSatoshis, fundingScript)
|
val fundingTxOut = TxOut(fundingSatoshis, fundingScript)
|
||||||
InputInfo.TaprootInput(OutPoint(fundingTxId, fundingTxOutputIndex), fundingTxOut, Taproot.musig2Aggregate(fundingPubkey1, fundingPubkey2), None)
|
InputInfo.TaprootInput(OutPoint(fundingTxId, fundingTxOutputIndex), fundingTxOut, Taproot.musig2Aggregate(fundingPubkey1, fundingPubkey2), None)
|
||||||
} else {
|
case _ =>
|
||||||
val fundingScript = multiSig2of2(fundingPubkey1, fundingPubkey2)
|
val fundingScript = multiSig2of2(fundingPubkey1, fundingPubkey2)
|
||||||
val fundingTxOut = TxOut(fundingSatoshis, pay2wsh(fundingScript))
|
val fundingTxOut = TxOut(fundingSatoshis, pay2wsh(fundingScript))
|
||||||
InputInfo.SegwitInput(OutPoint(fundingTxId, fundingTxOutputIndex), fundingTxOut, write(fundingScript))
|
InputInfo.SegwitInput(OutPoint(fundingTxId, fundingTxOutputIndex), fundingTxOut, write(fundingScript))
|
||||||
|
@ -661,7 +663,7 @@ object Helpers {
|
||||||
case DefaultCommitmentFormat =>
|
case DefaultCommitmentFormat =>
|
||||||
// we "MUST set fee_satoshis less than or equal to the base fee of the final commitment transaction"
|
// we "MUST set fee_satoshis less than or equal to the base fee of the final commitment transaction"
|
||||||
requestedFeerate.min(commitment.localCommit.spec.commitTxFeerate)
|
requestedFeerate.min(commitment.localCommit.spec.commitTxFeerate)
|
||||||
case _: AnchorOutputsCommitmentFormat => requestedFeerate
|
case _: AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat => requestedFeerate
|
||||||
}
|
}
|
||||||
// NB: we choose a minimum fee that ensures the tx will easily propagate while allowing low fees since we can
|
// NB: we choose a minimum fee that ensures the tx will easily propagate while allowing low fees since we can
|
||||||
// always use CPFP to speed up confirmation if necessary.
|
// always use CPFP to speed up confirmation if necessary.
|
||||||
|
@ -892,18 +894,18 @@ object Helpers {
|
||||||
def claimAnchors(keyManager: ChannelKeyManager, commitment: FullCommitment, lcp: LocalCommitPublished, confirmationTarget: ConfirmationTarget)(implicit log: LoggingAdapter): LocalCommitPublished = {
|
def claimAnchors(keyManager: ChannelKeyManager, commitment: FullCommitment, lcp: LocalCommitPublished, confirmationTarget: ConfirmationTarget)(implicit log: LoggingAdapter): LocalCommitPublished = {
|
||||||
if (shouldUpdateAnchorTxs(lcp.claimAnchorTxs, confirmationTarget)) {
|
if (shouldUpdateAnchorTxs(lcp.claimAnchorTxs, confirmationTarget)) {
|
||||||
val localFundingPubKey = keyManager.fundingPublicKey(commitment.localParams.fundingKeyPath, commitment.fundingTxIndex).publicKey
|
val localFundingPubKey = keyManager.fundingPublicKey(commitment.localParams.fundingKeyPath, commitment.fundingTxIndex).publicKey
|
||||||
val localPaymentKey = if (commitment.params.commitmentFormat.useTaproot) {
|
val localPaymentKey = commitment.params.commitmentFormat match {
|
||||||
|
case SimpleTaprootChannelCommitmentFormat =>
|
||||||
val channelKeyPath = keyManager.keyPath(commitment.localParams, commitment.params.channelConfig)
|
val channelKeyPath = keyManager.keyPath(commitment.localParams, commitment.params.channelConfig)
|
||||||
val localPerCommitmentPoint = keyManager.commitmentPoint(channelKeyPath, commitment.localCommit.index)
|
val localPerCommitmentPoint = keyManager.commitmentPoint(channelKeyPath, commitment.localCommit.index)
|
||||||
val localDelayedPaymentPubkey = Generators.derivePubKey(keyManager.delayedPaymentPoint(channelKeyPath).publicKey, localPerCommitmentPoint)
|
val localDelayedPaymentPubkey = Generators.derivePubKey(keyManager.delayedPaymentPoint(channelKeyPath).publicKey, localPerCommitmentPoint)
|
||||||
localDelayedPaymentPubkey
|
localDelayedPaymentPubkey
|
||||||
} else {
|
case _ =>
|
||||||
localFundingPubKey
|
localFundingPubKey
|
||||||
}
|
}
|
||||||
val remotePaymentKey = if (commitment.params.commitmentFormat.useTaproot) {
|
val remotePaymentKey = commitment.params.commitmentFormat match {
|
||||||
commitment.remoteParams.paymentBasepoint
|
case SimpleTaprootChannelCommitmentFormat => commitment.remoteParams.paymentBasepoint
|
||||||
} else {
|
case _ => commitment.remoteFundingPubKey
|
||||||
commitment.remoteFundingPubKey
|
|
||||||
}
|
}
|
||||||
val claimAnchorTxs = List(
|
val claimAnchorTxs = List(
|
||||||
withTxGenerationLog("local-anchor") {
|
withTxGenerationLog("local-anchor") {
|
||||||
|
@ -1028,16 +1030,18 @@ object Helpers {
|
||||||
val localFundingPubkey = keyManager.fundingPublicKey(commitment.localParams.fundingKeyPath, commitment.fundingTxIndex).publicKey
|
val localFundingPubkey = keyManager.fundingPublicKey(commitment.localParams.fundingKeyPath, commitment.fundingTxIndex).publicKey
|
||||||
|
|
||||||
// taproot channels do not re-use the funding pubkeys for anchor outputs
|
// taproot channels do not re-use the funding pubkeys for anchor outputs
|
||||||
val localPaymentKey = if (commitment.params.commitmentFormat.useTaproot) {
|
val localPaymentKey = commitment.params.commitmentFormat match {
|
||||||
|
case SimpleTaprootChannelCommitmentFormat =>
|
||||||
val channelKeyPath = keyManager.keyPath(commitment.localParams, commitment.params.channelConfig)
|
val channelKeyPath = keyManager.keyPath(commitment.localParams, commitment.params.channelConfig)
|
||||||
commitment.localParams.walletStaticPaymentBasepoint.getOrElse(keyManager.paymentPoint(channelKeyPath).publicKey)
|
commitment.localParams.walletStaticPaymentBasepoint.getOrElse(keyManager.paymentPoint(channelKeyPath).publicKey)
|
||||||
} else {
|
case _ =>
|
||||||
localFundingPubkey
|
localFundingPubkey
|
||||||
}
|
}
|
||||||
val remotePaymentKey = if (commitment.params.commitmentFormat.useTaproot) {
|
val remotePaymentKey = commitment.params.commitmentFormat match {
|
||||||
|
case SimpleTaprootChannelCommitmentFormat =>
|
||||||
val remoteDelayedPaymentPubkey = Generators.derivePubKey(commitment.remoteParams.delayedPaymentBasepoint, commitment.remoteCommit.remotePerCommitmentPoint)
|
val remoteDelayedPaymentPubkey = Generators.derivePubKey(commitment.remoteParams.delayedPaymentBasepoint, commitment.remoteCommit.remotePerCommitmentPoint)
|
||||||
remoteDelayedPaymentPubkey
|
remoteDelayedPaymentPubkey
|
||||||
} else {
|
case _ =>
|
||||||
commitment.remoteFundingPubKey
|
commitment.remoteFundingPubKey
|
||||||
}
|
}
|
||||||
val claimAnchorTxs = List(
|
val claimAnchorTxs = List(
|
||||||
|
@ -1078,7 +1082,7 @@ object Helpers {
|
||||||
Transactions.addSigs(claimMain, localPubkey, sig)
|
Transactions.addSigs(claimMain, localPubkey, sig)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
case _: AnchorOutputsCommitmentFormat => withTxGenerationLog("remote-main-delayed") {
|
case _: AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat => withTxGenerationLog("remote-main-delayed") {
|
||||||
Transactions.makeClaimRemoteDelayedOutputTx(tx, params.localParams.dustLimit, localPaymentPoint, finalScriptPubKey, feeratePerKwMain).map(claimMain => {
|
Transactions.makeClaimRemoteDelayedOutputTx(tx, params.localParams.dustLimit, localPaymentPoint, finalScriptPubKey, feeratePerKwMain).map(claimMain => {
|
||||||
val sig = keyManager.sign(claimMain, keyManager.paymentPoint(channelKeyPath), TxOwner.Local, params.commitmentFormat)
|
val sig = keyManager.sign(claimMain, keyManager.paymentPoint(channelKeyPath), TxOwner.Local, params.commitmentFormat)
|
||||||
Transactions.addSigs(claimMain, sig)
|
Transactions.addSigs(claimMain, sig)
|
||||||
|
@ -1214,7 +1218,7 @@ object Helpers {
|
||||||
Transactions.addSigs(claimMain, localPaymentPubkey, sig)
|
Transactions.addSigs(claimMain, localPaymentPubkey, sig)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
case _: AnchorOutputsCommitmentFormat => withTxGenerationLog("remote-main-delayed") {
|
case _: AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat => withTxGenerationLog("remote-main-delayed") {
|
||||||
Transactions.makeClaimRemoteDelayedOutputTx(commitTx, localParams.dustLimit, localPaymentPoint, finalScriptPubKey, feerateMain).map(claimMain => {
|
Transactions.makeClaimRemoteDelayedOutputTx(commitTx, localParams.dustLimit, localPaymentPoint, finalScriptPubKey, feerateMain).map(claimMain => {
|
||||||
val sig = keyManager.sign(claimMain, keyManager.paymentPoint(channelKeyPath), TxOwner.Local, commitmentFormat)
|
val sig = keyManager.sign(claimMain, keyManager.paymentPoint(channelKeyPath), TxOwner.Local, commitmentFormat)
|
||||||
Transactions.addSigs(claimMain, sig)
|
Transactions.addSigs(claimMain, sig)
|
||||||
|
|
|
@ -237,7 +237,7 @@ trait ErrorHandlers extends CommonHandlers {
|
||||||
case Transactions.DefaultCommitmentFormat =>
|
case Transactions.DefaultCommitmentFormat =>
|
||||||
val redeemableHtlcTxs = htlcTxs.values.flatten.map(tx => PublishFinalTx(tx, tx.fee, Some(commitTx.txid)))
|
val redeemableHtlcTxs = htlcTxs.values.flatten.map(tx => PublishFinalTx(tx, tx.fee, Some(commitTx.txid)))
|
||||||
List(PublishFinalTx(commitTx, commitment.commitInput.outPoint, commitment.capacity, "commit-tx", Closing.commitTxFee(commitment.commitInput, commitTx, localPaysCommitTxFees), None)) ++ (claimMainDelayedOutputTx.map(tx => PublishFinalTx(tx, tx.fee, None)) ++ redeemableHtlcTxs ++ claimHtlcDelayedTxs.map(tx => PublishFinalTx(tx, tx.fee, None)))
|
List(PublishFinalTx(commitTx, commitment.commitInput.outPoint, commitment.capacity, "commit-tx", Closing.commitTxFee(commitment.commitInput, commitTx, localPaysCommitTxFees), None)) ++ (claimMainDelayedOutputTx.map(tx => PublishFinalTx(tx, tx.fee, None)) ++ redeemableHtlcTxs ++ claimHtlcDelayedTxs.map(tx => PublishFinalTx(tx, tx.fee, None)))
|
||||||
case _: Transactions.AnchorOutputsCommitmentFormat =>
|
case _: Transactions.AnchorOutputsCommitmentFormat | Transactions.SimpleTaprootChannelCommitmentFormat =>
|
||||||
val redeemableHtlcTxs = htlcTxs.values.flatten.map(tx => PublishReplaceableTx(tx, commitment, commitTx))
|
val redeemableHtlcTxs = htlcTxs.values.flatten.map(tx => PublishReplaceableTx(tx, commitment, commitTx))
|
||||||
val claimLocalAnchor = claimAnchorTxs.collect { case tx: Transactions.ClaimLocalAnchorOutputTx if !localCommitPublished.isConfirmed => PublishReplaceableTx(tx, commitment, commitTx) }
|
val claimLocalAnchor = claimAnchorTxs.collect { case tx: Transactions.ClaimLocalAnchorOutputTx if !localCommitPublished.isConfirmed => PublishReplaceableTx(tx, commitment, commitTx) }
|
||||||
List(PublishFinalTx(commitTx, commitment.commitInput.outPoint, commitment.capacity, "commit-tx", Closing.commitTxFee(commitment.commitInput, commitTx, localPaysCommitTxFees), None)) ++ claimLocalAnchor ++ claimMainDelayedOutputTx.map(tx => PublishFinalTx(tx, tx.fee, None)) ++ redeemableHtlcTxs ++ claimHtlcDelayedTxs.map(tx => PublishFinalTx(tx, tx.fee, None))
|
List(PublishFinalTx(commitTx, commitment.commitInput.outPoint, commitment.capacity, "commit-tx", Closing.commitTxFee(commitment.commitInput, commitTx, localPaysCommitTxFees), None)) ++ claimLocalAnchor ++ claimMainDelayedOutputTx.map(tx => PublishFinalTx(tx, tx.fee, None)) ++ redeemableHtlcTxs ++ claimHtlcDelayedTxs.map(tx => PublishFinalTx(tx, tx.fee, None))
|
||||||
|
|
|
@ -23,7 +23,7 @@ import fr.acinq.bitcoin.TxIn.{SEQUENCE_LOCKTIME_DISABLE_FLAG, SEQUENCE_LOCKTIME_
|
||||||
import fr.acinq.bitcoin.scalacompat.Crypto.{PublicKey, XonlyPublicKey}
|
import fr.acinq.bitcoin.scalacompat.Crypto.{PublicKey, XonlyPublicKey}
|
||||||
import fr.acinq.bitcoin.scalacompat.Script._
|
import fr.acinq.bitcoin.scalacompat.Script._
|
||||||
import fr.acinq.bitcoin.scalacompat._
|
import fr.acinq.bitcoin.scalacompat._
|
||||||
import fr.acinq.eclair.transactions.Transactions.{AnchorOutputsCommitmentFormat, CommitmentFormat, DefaultCommitmentFormat}
|
import fr.acinq.eclair.transactions.Transactions.{AnchorOutputsCommitmentFormat, CommitmentFormat, DefaultCommitmentFormat, SimpleTaprootChannelCommitmentFormat}
|
||||||
import fr.acinq.eclair.{BlockHeight, CltvExpiry, CltvExpiryDelta}
|
import fr.acinq.eclair.{BlockHeight, CltvExpiry, CltvExpiryDelta}
|
||||||
import scodec.bits.ByteVector
|
import scodec.bits.ByteVector
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ object Scripts {
|
||||||
|
|
||||||
private def htlcRemoteSighash(commitmentFormat: CommitmentFormat): Int = commitmentFormat match {
|
private def htlcRemoteSighash(commitmentFormat: CommitmentFormat): Int = commitmentFormat match {
|
||||||
case DefaultCommitmentFormat => SIGHASH_ALL
|
case DefaultCommitmentFormat => SIGHASH_ALL
|
||||||
case _: AnchorOutputsCommitmentFormat => SIGHASH_SINGLE | SIGHASH_ANYONECANPAY
|
case _: AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat => SIGHASH_SINGLE | SIGHASH_ANYONECANPAY
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sort public keys using lexicographic ordering. */
|
/** Sort public keys using lexicographic ordering. */
|
||||||
|
@ -191,6 +191,7 @@ object Scripts {
|
||||||
val addCsvDelay = commitmentFormat match {
|
val addCsvDelay = commitmentFormat match {
|
||||||
case DefaultCommitmentFormat => false
|
case DefaultCommitmentFormat => false
|
||||||
case _: AnchorOutputsCommitmentFormat => true
|
case _: AnchorOutputsCommitmentFormat => true
|
||||||
|
case SimpleTaprootChannelCommitmentFormat => true
|
||||||
}
|
}
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
// To you with revocation key
|
// To you with revocation key
|
||||||
|
@ -243,6 +244,7 @@ object Scripts {
|
||||||
val addCsvDelay = commitmentFormat match {
|
val addCsvDelay = commitmentFormat match {
|
||||||
case DefaultCommitmentFormat => false
|
case DefaultCommitmentFormat => false
|
||||||
case _: AnchorOutputsCommitmentFormat => true
|
case _: AnchorOutputsCommitmentFormat => true
|
||||||
|
case SimpleTaprootChannelCommitmentFormat => true
|
||||||
}
|
}
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
// To you with revocation key
|
// To you with revocation key
|
||||||
|
|
|
@ -52,7 +52,6 @@ object Transactions {
|
||||||
def htlcSuccessWeight: Int
|
def htlcSuccessWeight: Int
|
||||||
def htlcTimeoutInputWeight: Int
|
def htlcTimeoutInputWeight: Int
|
||||||
def htlcSuccessInputWeight: Int
|
def htlcSuccessInputWeight: Int
|
||||||
def useTaproot: Boolean = false
|
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,9 +97,13 @@ object Transactions {
|
||||||
*/
|
*/
|
||||||
case object ZeroFeeHtlcTxAnchorOutputsCommitmentFormat extends AnchorOutputsCommitmentFormat
|
case object ZeroFeeHtlcTxAnchorOutputsCommitmentFormat extends AnchorOutputsCommitmentFormat
|
||||||
|
|
||||||
case object SimpleTaprootChannelCommitmentFormat extends AnchorOutputsCommitmentFormat {
|
case object SimpleTaprootChannelCommitmentFormat extends CommitmentFormat {
|
||||||
override val commitWeight = 968
|
override val commitWeight = 968
|
||||||
override val useTaproot = true
|
override val htlcOutputWeight = 172
|
||||||
|
override val htlcTimeoutWeight = 666
|
||||||
|
override val htlcSuccessWeight = 706
|
||||||
|
override val htlcTimeoutInputWeight = 452
|
||||||
|
override val htlcSuccessInputWeight = 491
|
||||||
}
|
}
|
||||||
|
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
|
@ -144,7 +147,10 @@ object Transactions {
|
||||||
Satoshi(FeeratePerKw.MinimumRelayFeeRate * vsize / 1000)
|
Satoshi(FeeratePerKw.MinimumRelayFeeRate * vsize / 1000)
|
||||||
}
|
}
|
||||||
/** Sighash flags to use when signing the transaction. */
|
/** Sighash flags to use when signing the transaction. */
|
||||||
def sighash(txOwner: TxOwner, commitmentFormat: CommitmentFormat): Int = if (input.isP2tr) SIGHASH_DEFAULT else SIGHASH_ALL
|
def sighash(txOwner: TxOwner, commitmentFormat: CommitmentFormat): Int = commitmentFormat match {
|
||||||
|
case SimpleTaprootChannelCommitmentFormat => SIGHASH_DEFAULT
|
||||||
|
case _ => SIGHASH_ALL
|
||||||
|
}
|
||||||
|
|
||||||
def sign(key: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = {
|
def sign(key: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = {
|
||||||
sign(key, sighash(txOwner, commitmentFormat))
|
sign(key, sighash(txOwner, commitmentFormat))
|
||||||
|
@ -218,6 +224,10 @@ object Transactions {
|
||||||
case TxOwner.Local => SIGHASH_ALL
|
case TxOwner.Local => SIGHASH_ALL
|
||||||
case TxOwner.Remote => SIGHASH_SINGLE | SIGHASH_ANYONECANPAY
|
case TxOwner.Remote => SIGHASH_SINGLE | SIGHASH_ANYONECANPAY
|
||||||
}
|
}
|
||||||
|
case SimpleTaprootChannelCommitmentFormat => txOwner match {
|
||||||
|
case TxOwner.Local => SIGHASH_DEFAULT
|
||||||
|
case TxOwner.Remote => SIGHASH_SINGLE | SIGHASH_ANYONECANPAY
|
||||||
|
}
|
||||||
}
|
}
|
||||||
override def confirmationTarget: ConfirmationTarget.Absolute
|
override def confirmationTarget: ConfirmationTarget.Absolute
|
||||||
}
|
}
|
||||||
|
@ -228,7 +238,7 @@ object Transactions {
|
||||||
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
||||||
case t: InputInfo.TaprootInput =>
|
case t: InputInfo.TaprootInput =>
|
||||||
val Some(scriptTree: ScriptTree.Branch) = t.scriptTree_opt
|
val Some(scriptTree: ScriptTree.Branch) = t.scriptTree_opt
|
||||||
Transaction.signInputTaprootScriptPath(privateKey, tx, 0, Seq(input.txOut), SigHash.SIGHASH_SINGLE | SigHash.SIGHASH_ANYONECANPAY, KotlinUtils.kmp2scala(scriptTree.getRight.hash()))
|
Transaction.signInputTaprootScriptPath(privateKey, tx, 0, Seq(input.txOut), sighash(txOwner, commitmentFormat), KotlinUtils.kmp2scala(scriptTree.getRight.hash()))
|
||||||
case _: InputInfo.SegwitInput =>
|
case _: InputInfo.SegwitInput =>
|
||||||
super.sign(privateKey, txOwner, commitmentFormat)
|
super.sign(privateKey, txOwner, commitmentFormat)
|
||||||
}
|
}
|
||||||
|
@ -236,9 +246,8 @@ object Transactions {
|
||||||
override def checkSig(sig: ByteVector64, pubKey: PublicKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): Boolean = input match {
|
override def checkSig(sig: ByteVector64, pubKey: PublicKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): Boolean = input match {
|
||||||
case t: InputInfo.TaprootInput =>
|
case t: InputInfo.TaprootInput =>
|
||||||
import KotlinUtils._
|
import KotlinUtils._
|
||||||
val sighash = this.sighash(txOwner, commitmentFormat)
|
|
||||||
val Some(scriptTree: ScriptTree.Branch) = t.scriptTree_opt
|
val Some(scriptTree: ScriptTree.Branch) = t.scriptTree_opt
|
||||||
val data = Transaction.hashForSigningTaprootScriptPath(tx, inputIndex = 0, Seq(input.txOut), sighash, scriptTree.getRight.hash())
|
val data = Transaction.hashForSigningTaprootScriptPath(tx, inputIndex = 0, Seq(input.txOut), sighash(txOwner, commitmentFormat), scriptTree.getRight.hash())
|
||||||
Crypto.verifySignatureSchnorr(data, sig, pubKey.xOnly)
|
Crypto.verifySignatureSchnorr(data, sig, pubKey.xOnly)
|
||||||
case _: InputInfo.SegwitInput =>
|
case _: InputInfo.SegwitInput =>
|
||||||
super.checkSig(sig, pubKey, txOwner, commitmentFormat)
|
super.checkSig(sig, pubKey, txOwner, commitmentFormat)
|
||||||
|
@ -251,7 +260,7 @@ object Transactions {
|
||||||
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
||||||
case t: InputInfo.TaprootInput =>
|
case t: InputInfo.TaprootInput =>
|
||||||
val Some(scriptTree: ScriptTree.Branch) = t.scriptTree_opt
|
val Some(scriptTree: ScriptTree.Branch) = t.scriptTree_opt
|
||||||
Transaction.signInputTaprootScriptPath(privateKey, tx, 0, Seq(input.txOut), SigHash.SIGHASH_SINGLE | SigHash.SIGHASH_ANYONECANPAY, KotlinUtils.kmp2scala(scriptTree.getLeft.hash()))
|
Transaction.signInputTaprootScriptPath(privateKey, tx, 0, Seq(input.txOut), sighash(txOwner, commitmentFormat), KotlinUtils.kmp2scala(scriptTree.getLeft.hash()))
|
||||||
case _: InputInfo.SegwitInput =>
|
case _: InputInfo.SegwitInput =>
|
||||||
super.sign(privateKey, txOwner, commitmentFormat)
|
super.sign(privateKey, txOwner, commitmentFormat)
|
||||||
}
|
}
|
||||||
|
@ -259,9 +268,8 @@ object Transactions {
|
||||||
override def checkSig(sig: ByteVector64, pubKey: PublicKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): Boolean = input match {
|
override def checkSig(sig: ByteVector64, pubKey: PublicKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): Boolean = input match {
|
||||||
case t: InputInfo.TaprootInput =>
|
case t: InputInfo.TaprootInput =>
|
||||||
import KotlinUtils._
|
import KotlinUtils._
|
||||||
val sighash = this.sighash(txOwner, commitmentFormat)
|
|
||||||
val Some(scriptTree: ScriptTree.Branch) = t.scriptTree_opt
|
val Some(scriptTree: ScriptTree.Branch) = t.scriptTree_opt
|
||||||
val data = Transaction.hashForSigningTaprootScriptPath(tx, inputIndex = 0, Seq(input.txOut), sighash, scriptTree.getLeft.hash())
|
val data = Transaction.hashForSigningTaprootScriptPath(tx, inputIndex = 0, Seq(input.txOut), sighash(txOwner, commitmentFormat), scriptTree.getLeft.hash())
|
||||||
Crypto.verifySignatureSchnorr(data, sig, pubKey.xOnly)
|
Crypto.verifySignatureSchnorr(data, sig, pubKey.xOnly)
|
||||||
case _: InputInfo.SegwitInput =>
|
case _: InputInfo.SegwitInput =>
|
||||||
super.checkSig(sig, pubKey, txOwner, commitmentFormat)
|
super.checkSig(sig, pubKey, txOwner, commitmentFormat)
|
||||||
|
@ -273,7 +281,7 @@ object Transactions {
|
||||||
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
||||||
case t: InputInfo.TaprootInput =>
|
case t: InputInfo.TaprootInput =>
|
||||||
val Some(scriptTree: ScriptTree.Leaf) = t.scriptTree_opt
|
val Some(scriptTree: ScriptTree.Leaf) = t.scriptTree_opt
|
||||||
Transaction.signInputTaprootScriptPath(privateKey, tx, 0, Seq(input.txOut), SigHash.SIGHASH_DEFAULT, KotlinUtils.kmp2scala(scriptTree.hash()))
|
Transaction.signInputTaprootScriptPath(privateKey, tx, 0, Seq(input.txOut), sighash(txOwner, commitmentFormat), KotlinUtils.kmp2scala(scriptTree.hash()))
|
||||||
case _: InputInfo.SegwitInput =>
|
case _: InputInfo.SegwitInput =>
|
||||||
super.sign(privateKey, txOwner, commitmentFormat)
|
super.sign(privateKey, txOwner, commitmentFormat)
|
||||||
}
|
}
|
||||||
|
@ -290,7 +298,7 @@ object Transactions {
|
||||||
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
||||||
case t: InputInfo.TaprootInput =>
|
case t: InputInfo.TaprootInput =>
|
||||||
val Some(htlcTree: ScriptTree.Branch) = t.scriptTree_opt
|
val Some(htlcTree: ScriptTree.Branch) = t.scriptTree_opt
|
||||||
Transaction.signInputTaprootScriptPath(privateKey, tx, 0, Seq(input.txOut), SigHash.SIGHASH_DEFAULT, KotlinUtils.kmp2scala(htlcTree.getRight.hash()))
|
Transaction.signInputTaprootScriptPath(privateKey, tx, 0, Seq(input.txOut), sighash(txOwner, commitmentFormat), KotlinUtils.kmp2scala(htlcTree.getRight.hash()))
|
||||||
case _: InputInfo.SegwitInput =>
|
case _: InputInfo.SegwitInput =>
|
||||||
super.sign(privateKey, txOwner, commitmentFormat)
|
super.sign(privateKey, txOwner, commitmentFormat)
|
||||||
}
|
}
|
||||||
|
@ -301,7 +309,7 @@ object Transactions {
|
||||||
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
||||||
case t: InputInfo.TaprootInput =>
|
case t: InputInfo.TaprootInput =>
|
||||||
val Some(htlcTree: ScriptTree.Branch) = t.scriptTree_opt
|
val Some(htlcTree: ScriptTree.Branch) = t.scriptTree_opt
|
||||||
Transaction.signInputTaprootScriptPath(privateKey, tx, 0, Seq(input.txOut), SigHash.SIGHASH_DEFAULT, KotlinUtils.kmp2scala(htlcTree.getLeft.hash()))
|
Transaction.signInputTaprootScriptPath(privateKey, tx, 0, Seq(input.txOut), sighash(txOwner, commitmentFormat), KotlinUtils.kmp2scala(htlcTree.getLeft.hash()))
|
||||||
case _: InputInfo.SegwitInput =>
|
case _: InputInfo.SegwitInput =>
|
||||||
super.sign(privateKey, txOwner, commitmentFormat)
|
super.sign(privateKey, txOwner, commitmentFormat)
|
||||||
}
|
}
|
||||||
|
@ -312,7 +320,7 @@ object Transactions {
|
||||||
override def desc: String = "local-anchor"
|
override def desc: String = "local-anchor"
|
||||||
|
|
||||||
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
||||||
case _: InputInfo.TaprootInput => Transaction.signInputTaprootKeyPath(privateKey, tx, 0, Seq(input.txOut), SigHash.SIGHASH_DEFAULT, Some(Scripts.Taproot.anchorScriptTree))
|
case _: InputInfo.TaprootInput => Transaction.signInputTaprootKeyPath(privateKey, tx, 0, Seq(input.txOut), sighash(txOwner, commitmentFormat), Some(Scripts.Taproot.anchorScriptTree))
|
||||||
case _: InputInfo.SegwitInput => super.sign(privateKey, txOwner, commitmentFormat)
|
case _: InputInfo.SegwitInput => super.sign(privateKey, txOwner, commitmentFormat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -326,7 +334,7 @@ object Transactions {
|
||||||
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
||||||
case t: InputInfo.TaprootInput =>
|
case t: InputInfo.TaprootInput =>
|
||||||
val Some(toRemoteScriptTree: ScriptTree.Leaf) = t.scriptTree_opt
|
val Some(toRemoteScriptTree: ScriptTree.Leaf) = t.scriptTree_opt
|
||||||
Transaction.signInputTaprootScriptPath(privateKey, tx, 0, Seq(input.txOut), SigHash.SIGHASH_DEFAULT, KotlinUtils.kmp2scala(toRemoteScriptTree.hash()))
|
Transaction.signInputTaprootScriptPath(privateKey, tx, 0, Seq(input.txOut), sighash(txOwner, commitmentFormat), KotlinUtils.kmp2scala(toRemoteScriptTree.hash()))
|
||||||
case _: InputInfo.SegwitInput => {
|
case _: InputInfo.SegwitInput => {
|
||||||
super.sign(privateKey, txOwner, commitmentFormat)
|
super.sign(privateKey, txOwner, commitmentFormat)
|
||||||
}
|
}
|
||||||
|
@ -339,7 +347,7 @@ object Transactions {
|
||||||
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
||||||
case t: InputInfo.TaprootInput =>
|
case t: InputInfo.TaprootInput =>
|
||||||
val Some(toLocalScriptTree: ScriptTree.Branch) = t.scriptTree_opt
|
val Some(toLocalScriptTree: ScriptTree.Branch) = t.scriptTree_opt
|
||||||
Transaction.signInputTaprootScriptPath(privateKey, tx, 0, Seq(input.txOut), SigHash.SIGHASH_DEFAULT, KotlinUtils.kmp2scala(toLocalScriptTree.getLeft.hash()))
|
Transaction.signInputTaprootScriptPath(privateKey, tx, 0, Seq(input.txOut), sighash(txOwner, commitmentFormat), KotlinUtils.kmp2scala(toLocalScriptTree.getLeft.hash()))
|
||||||
case _: InputInfo.SegwitInput => {
|
case _: InputInfo.SegwitInput => {
|
||||||
super.sign(privateKey, txOwner, commitmentFormat)
|
super.sign(privateKey, txOwner, commitmentFormat)
|
||||||
}
|
}
|
||||||
|
@ -352,7 +360,7 @@ object Transactions {
|
||||||
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
||||||
case t: InputInfo.TaprootInput =>
|
case t: InputInfo.TaprootInput =>
|
||||||
val Some(toLocalScriptTree: ScriptTree.Branch) = t.scriptTree_opt
|
val Some(toLocalScriptTree: ScriptTree.Branch) = t.scriptTree_opt
|
||||||
Transaction.signInputTaprootScriptPath(privateKey, tx, 0, Seq(input.txOut), SigHash.SIGHASH_DEFAULT, KotlinUtils.kmp2scala(toLocalScriptTree.getRight.hash()))
|
Transaction.signInputTaprootScriptPath(privateKey, tx, 0, Seq(input.txOut), sighash(txOwner, commitmentFormat), KotlinUtils.kmp2scala(toLocalScriptTree.getRight.hash()))
|
||||||
case _: InputInfo.SegwitInput => {
|
case _: InputInfo.SegwitInput => {
|
||||||
super.sign(privateKey, txOwner, commitmentFormat)
|
super.sign(privateKey, txOwner, commitmentFormat)
|
||||||
}
|
}
|
||||||
|
@ -364,7 +372,7 @@ object Transactions {
|
||||||
|
|
||||||
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
||||||
case t: InputInfo.TaprootInput =>
|
case t: InputInfo.TaprootInput =>
|
||||||
Transaction.signInputTaprootKeyPath(privateKey, tx, 0, Seq(input.txOut), SigHash.SIGHASH_DEFAULT, t.scriptTree_opt)
|
Transaction.signInputTaprootKeyPath(privateKey, tx, 0, Seq(input.txOut), sighash(txOwner, commitmentFormat), t.scriptTree_opt)
|
||||||
case _: InputInfo.SegwitInput => {
|
case _: InputInfo.SegwitInput => {
|
||||||
super.sign(privateKey, txOwner, commitmentFormat)
|
super.sign(privateKey, txOwner, commitmentFormat)
|
||||||
}
|
}
|
||||||
|
@ -376,7 +384,7 @@ object Transactions {
|
||||||
|
|
||||||
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
override def sign(privateKey: PrivateKey, txOwner: TxOwner, commitmentFormat: CommitmentFormat): ByteVector64 = input match {
|
||||||
case t: InputInfo.TaprootInput =>
|
case t: InputInfo.TaprootInput =>
|
||||||
Transaction.signInputTaprootKeyPath(privateKey, tx, 0, Seq(input.txOut), SigHash.SIGHASH_DEFAULT, t.scriptTree_opt)
|
Transaction.signInputTaprootKeyPath(privateKey, tx, 0, Seq(input.txOut), sighash(txOwner, commitmentFormat), t.scriptTree_opt)
|
||||||
case _: InputInfo.SegwitInput => {
|
case _: InputInfo.SegwitInput => {
|
||||||
super.sign(privateKey, txOwner, commitmentFormat)
|
super.sign(privateKey, txOwner, commitmentFormat)
|
||||||
}
|
}
|
||||||
|
@ -384,8 +392,6 @@ object Transactions {
|
||||||
}
|
}
|
||||||
|
|
||||||
case class ClosingTx(input: InputInfo, tx: Transaction, toLocalOutput: Option[OutputInfo]) extends TransactionWithInputInfo {
|
case class ClosingTx(input: InputInfo, tx: Transaction, toLocalOutput: Option[OutputInfo]) extends TransactionWithInputInfo {
|
||||||
// these nonces are generated on the fly at during a "simple" closing session and can be forgotten once the session ends
|
|
||||||
// @volatile var localNonce_opt: Option[(SecretNonce, IndividualNonce)] = None
|
|
||||||
override def desc: String = "closing"
|
override def desc: String = "closing"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,7 +535,7 @@ object Transactions {
|
||||||
// This is not technically a fee (it doesn't go to miners) but it also has to be deduced from the channel initiator's main output.
|
// This is not technically a fee (it doesn't go to miners) but it also has to be deduced from the channel initiator's main output.
|
||||||
val anchorsCost = commitmentFormat match {
|
val anchorsCost = commitmentFormat match {
|
||||||
case DefaultCommitmentFormat => Satoshi(0)
|
case DefaultCommitmentFormat => Satoshi(0)
|
||||||
case _: AnchorOutputsCommitmentFormat => AnchorOutputsCommitmentFormat.anchorAmount * 2
|
case _: AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat => AnchorOutputsCommitmentFormat.anchorAmount * 2
|
||||||
}
|
}
|
||||||
txFee + anchorsCost
|
txFee + anchorsCost
|
||||||
}
|
}
|
||||||
|
@ -583,7 +589,7 @@ object Transactions {
|
||||||
|
|
||||||
def getHtlcTxInputSequence(commitmentFormat: CommitmentFormat): Long = commitmentFormat match {
|
def getHtlcTxInputSequence(commitmentFormat: CommitmentFormat): Long = commitmentFormat match {
|
||||||
case DefaultCommitmentFormat => 0 // htlc txs immediately spend the commit tx
|
case DefaultCommitmentFormat => 0 // htlc txs immediately spend the commit tx
|
||||||
case _: AnchorOutputsCommitmentFormat => 1 // htlc txs have a 1-block delay to allow CPFP carve-out on anchors
|
case _: AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat => 1 // htlc txs have a 1-block delay to allow CPFP carve-out on anchors
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -645,8 +651,8 @@ object Transactions {
|
||||||
val outputs = collection.mutable.ArrayBuffer.empty[CommitmentOutputLink[CommitmentOutput]]
|
val outputs = collection.mutable.ArrayBuffer.empty[CommitmentOutputLink[CommitmentOutput]]
|
||||||
|
|
||||||
trimOfferedHtlcs(localDustLimit, spec, commitmentFormat).foreach { htlc =>
|
trimOfferedHtlcs(localDustLimit, spec, commitmentFormat).foreach { htlc =>
|
||||||
commitmentFormat.useTaproot match {
|
commitmentFormat match {
|
||||||
case true =>
|
case SimpleTaprootChannelCommitmentFormat =>
|
||||||
val offeredHtlcTree = Scripts.Taproot.offeredHtlcScriptTree(localHtlcPubkey, remoteHtlcPubkey, htlc.add.paymentHash)
|
val offeredHtlcTree = Scripts.Taproot.offeredHtlcScriptTree(localHtlcPubkey, remoteHtlcPubkey, htlc.add.paymentHash)
|
||||||
outputs.append(CommitmentOutputLink(
|
outputs.append(CommitmentOutputLink(
|
||||||
TxOut(htlc.add.amountMsat.truncateToSatoshi, pay2tr(localRevocationPubkey.xOnly, Some(offeredHtlcTree))), localRevocationPubkey.xOnly, offeredHtlcTree, OutHtlc(htlc)
|
TxOut(htlc.add.amountMsat.truncateToSatoshi, pay2tr(localRevocationPubkey.xOnly, Some(offeredHtlcTree))), localRevocationPubkey.xOnly, offeredHtlcTree, OutHtlc(htlc)
|
||||||
|
@ -658,8 +664,8 @@ object Transactions {
|
||||||
}
|
}
|
||||||
|
|
||||||
trimReceivedHtlcs(localDustLimit, spec, commitmentFormat).foreach { htlc =>
|
trimReceivedHtlcs(localDustLimit, spec, commitmentFormat).foreach { htlc =>
|
||||||
commitmentFormat.useTaproot match {
|
commitmentFormat match {
|
||||||
case true =>
|
case SimpleTaprootChannelCommitmentFormat =>
|
||||||
val receivedHtlcTree = Scripts.Taproot.receivedHtlcScriptTree(localHtlcPubkey, remoteHtlcPubkey, htlc.add.paymentHash, htlc.add.cltvExpiry)
|
val receivedHtlcTree = Scripts.Taproot.receivedHtlcScriptTree(localHtlcPubkey, remoteHtlcPubkey, htlc.add.paymentHash, htlc.add.cltvExpiry)
|
||||||
outputs.append(CommitmentOutputLink(
|
outputs.append(CommitmentOutputLink(
|
||||||
TxOut(htlc.add.amountMsat.truncateToSatoshi, pay2tr(localRevocationPubkey.xOnly, Some(receivedHtlcTree))), localRevocationPubkey.xOnly, receivedHtlcTree, InHtlc(htlc)
|
TxOut(htlc.add.amountMsat.truncateToSatoshi, pay2tr(localRevocationPubkey.xOnly, Some(receivedHtlcTree))), localRevocationPubkey.xOnly, receivedHtlcTree, InHtlc(htlc)
|
||||||
|
@ -679,13 +685,14 @@ object Transactions {
|
||||||
} // NB: we don't care if values are < 0, they will be trimmed if they are < dust limit anyway
|
} // NB: we don't care if values are < 0, they will be trimmed if they are < dust limit anyway
|
||||||
|
|
||||||
if (toLocalAmount >= localDustLimit) {
|
if (toLocalAmount >= localDustLimit) {
|
||||||
if (commitmentFormat.useTaproot) {
|
commitmentFormat match {
|
||||||
|
case SimpleTaprootChannelCommitmentFormat =>
|
||||||
val toLocalScriptTree = Scripts.Taproot.toLocalScriptTree(localRevocationPubkey, toLocalDelay, localDelayedPaymentPubkey)
|
val toLocalScriptTree = Scripts.Taproot.toLocalScriptTree(localRevocationPubkey, toLocalDelay, localDelayedPaymentPubkey)
|
||||||
outputs.append(CommitmentOutputLink(
|
outputs.append(CommitmentOutputLink(
|
||||||
TxOut(toLocalAmount, pay2tr(XonlyPublicKey(NUMS_POINT), Some(toLocalScriptTree))),
|
TxOut(toLocalAmount, pay2tr(XonlyPublicKey(NUMS_POINT), Some(toLocalScriptTree))),
|
||||||
NUMS_POINT.xOnly, toLocalScriptTree,
|
NUMS_POINT.xOnly, toLocalScriptTree,
|
||||||
ToLocal))
|
ToLocal))
|
||||||
} else {
|
case _ =>
|
||||||
outputs.append(CommitmentOutputLink(
|
outputs.append(CommitmentOutputLink(
|
||||||
TxOut(toLocalAmount, pay2wsh(toLocalDelayed(localRevocationPubkey, toLocalDelay, localDelayedPaymentPubkey))),
|
TxOut(toLocalAmount, pay2wsh(toLocalDelayed(localRevocationPubkey, toLocalDelay, localDelayedPaymentPubkey))),
|
||||||
toLocalDelayed(localRevocationPubkey, toLocalDelay, localDelayedPaymentPubkey),
|
toLocalDelayed(localRevocationPubkey, toLocalDelay, localDelayedPaymentPubkey),
|
||||||
|
@ -695,7 +702,7 @@ object Transactions {
|
||||||
|
|
||||||
if (toRemoteAmount >= localDustLimit) {
|
if (toRemoteAmount >= localDustLimit) {
|
||||||
commitmentFormat match {
|
commitmentFormat match {
|
||||||
case _ if commitmentFormat.useTaproot =>
|
case SimpleTaprootChannelCommitmentFormat =>
|
||||||
val toRemoteScriptTree = Scripts.Taproot.toRemoteScriptTree(remotePaymentPubkey)
|
val toRemoteScriptTree = Scripts.Taproot.toRemoteScriptTree(remotePaymentPubkey)
|
||||||
outputs.append(CommitmentOutputLink(
|
outputs.append(CommitmentOutputLink(
|
||||||
TxOut(toRemoteAmount, pay2tr(XonlyPublicKey(NUMS_POINT), Some(toRemoteScriptTree))),
|
TxOut(toRemoteAmount, pay2tr(XonlyPublicKey(NUMS_POINT), Some(toRemoteScriptTree))),
|
||||||
|
@ -713,7 +720,7 @@ object Transactions {
|
||||||
}
|
}
|
||||||
|
|
||||||
commitmentFormat match {
|
commitmentFormat match {
|
||||||
case _ if commitmentFormat.useTaproot =>
|
case SimpleTaprootChannelCommitmentFormat =>
|
||||||
if (toLocalAmount >= localDustLimit || hasHtlcs) {
|
if (toLocalAmount >= localDustLimit || hasHtlcs) {
|
||||||
outputs.append(
|
outputs.append(
|
||||||
CommitmentOutputLink.TaprootLink(
|
CommitmentOutputLink.TaprootLink(
|
||||||
|
@ -1456,8 +1463,7 @@ object Transactions {
|
||||||
case t: InputInfo.TaprootInput =>
|
case t: InputInfo.TaprootInput =>
|
||||||
t.scriptTree_opt match {
|
t.scriptTree_opt match {
|
||||||
case Some(htlcTree: ScriptTree.Branch) =>
|
case Some(htlcTree: ScriptTree.Branch) =>
|
||||||
val sigHash = (SigHash.SIGHASH_SINGLE | SigHash.SIGHASH_ANYONECANPAY).toByte
|
Script.witnessScriptPathPay2tr(t.internalKey, htlcTree.getRight.asInstanceOf[ScriptTree.Leaf], ScriptWitness(Seq(Taproot.encodeSig(remoteSig, SigHash.SIGHASH_SINGLE | SigHash.SIGHASH_ANYONECANPAY), Taproot.encodeSig(localSig, SIGHASH_DEFAULT), paymentPreimage)), htlcTree)
|
||||||
Script.witnessScriptPathPay2tr(t.internalKey, htlcTree.getRight.asInstanceOf[ScriptTree.Leaf], ScriptWitness(Seq(remoteSig :+ sigHash, localSig :+ sigHash, paymentPreimage)), htlcTree)
|
|
||||||
case _ => throw new IllegalArgumentException("unexpected script tree leaf when building htlc successTx tx")
|
case _ => throw new IllegalArgumentException("unexpected script tree leaf when building htlc successTx tx")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1470,8 +1476,7 @@ object Transactions {
|
||||||
case t: InputInfo.TaprootInput =>
|
case t: InputInfo.TaprootInput =>
|
||||||
t.scriptTree_opt match {
|
t.scriptTree_opt match {
|
||||||
case Some(htlcTree: ScriptTree.Branch) =>
|
case Some(htlcTree: ScriptTree.Branch) =>
|
||||||
val sigHash = (SigHash.SIGHASH_SINGLE | SigHash.SIGHASH_ANYONECANPAY).toByte
|
Script.witnessScriptPathPay2tr(t.internalKey, htlcTree.getLeft.asInstanceOf[ScriptTree.Leaf], ScriptWitness(Seq(Taproot.encodeSig(remoteSig, SigHash.SIGHASH_SINGLE | SigHash.SIGHASH_ANYONECANPAY), Taproot.encodeSig(localSig, SIGHASH_DEFAULT))), htlcTree)
|
||||||
Script.witnessScriptPathPay2tr(t.internalKey, htlcTree.getLeft.asInstanceOf[ScriptTree.Leaf], ScriptWitness(Seq(remoteSig :+ sigHash, localSig :+ sigHash)), htlcTree)
|
|
||||||
case _ => throw new IllegalArgumentException("unexpected script tree leaf when building htlc timeout tx")
|
case _ => throw new IllegalArgumentException("unexpected script tree leaf when building htlc timeout tx")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1572,7 +1572,7 @@ class ReplaceableTxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike w
|
||||||
val remoteCommitTx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.fullySignedLocalCommitTx(bob.underlyingActor.nodeParams.channelKeyManager)
|
val remoteCommitTx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.fullySignedLocalCommitTx(bob.underlyingActor.nodeParams.channelKeyManager)
|
||||||
bob.stateData.asInstanceOf[DATA_NORMAL].commitments.params.commitmentFormat match {
|
bob.stateData.asInstanceOf[DATA_NORMAL].commitments.params.commitmentFormat match {
|
||||||
case Transactions.DefaultCommitmentFormat => assert(remoteCommitTx.tx.txOut.size == 4)
|
case Transactions.DefaultCommitmentFormat => assert(remoteCommitTx.tx.txOut.size == 4)
|
||||||
case _: AnchorOutputsCommitmentFormat => assert(remoteCommitTx.tx.txOut.size == 6)
|
case _: AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat => assert(remoteCommitTx.tx.txOut.size == 6)
|
||||||
}
|
}
|
||||||
probe.send(alice, WatchFundingSpentTriggered(remoteCommitTx.tx))
|
probe.send(alice, WatchFundingSpentTriggered(remoteCommitTx.tx))
|
||||||
|
|
||||||
|
@ -1583,7 +1583,7 @@ class ReplaceableTxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike w
|
||||||
|
|
||||||
bob.stateData.asInstanceOf[DATA_NORMAL].commitments.params.commitmentFormat match {
|
bob.stateData.asInstanceOf[DATA_NORMAL].commitments.params.commitmentFormat match {
|
||||||
case Transactions.DefaultCommitmentFormat => ()
|
case Transactions.DefaultCommitmentFormat => ()
|
||||||
case _: AnchorOutputsCommitmentFormat => alice2blockchain.expectMsgType[PublishReplaceableTx] // claim anchor
|
case _: AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat => alice2blockchain.expectMsgType[PublishReplaceableTx] // claim anchor
|
||||||
}
|
}
|
||||||
if (!bob.stateData.asInstanceOf[DATA_NORMAL].commitments.params.channelFeatures.paysDirectlyToWallet) alice2blockchain.expectMsgType[PublishFinalTx] // claim main output
|
if (!bob.stateData.asInstanceOf[DATA_NORMAL].commitments.params.channelFeatures.paysDirectlyToWallet) alice2blockchain.expectMsgType[PublishFinalTx] // claim main output
|
||||||
val claimHtlcSuccess = alice2blockchain.expectMsgType[PublishReplaceableTx]
|
val claimHtlcSuccess = alice2blockchain.expectMsgType[PublishReplaceableTx]
|
||||||
|
|
|
@ -590,7 +590,7 @@ trait ChannelStateTestsBase extends Assertions with Eventually {
|
||||||
// all htlcs success/timeout should be published as-is, without claiming their outputs
|
// all htlcs success/timeout should be published as-is, without claiming their outputs
|
||||||
s2blockchain.expectMsgAllOf(localCommitPublished.htlcTxs.values.toSeq.collect { case Some(tx) => TxPublisher.PublishFinalTx(tx, tx.fee, Some(commitTx.txid)) }: _*)
|
s2blockchain.expectMsgAllOf(localCommitPublished.htlcTxs.values.toSeq.collect { case Some(tx) => TxPublisher.PublishFinalTx(tx, tx.fee, Some(commitTx.txid)) }: _*)
|
||||||
assert(localCommitPublished.claimHtlcDelayedTxs.isEmpty)
|
assert(localCommitPublished.claimHtlcDelayedTxs.isEmpty)
|
||||||
case _: Transactions.AnchorOutputsCommitmentFormat =>
|
case _: Transactions.AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat =>
|
||||||
// all htlcs success/timeout should be published as replaceable txs, without claiming their outputs
|
// all htlcs success/timeout should be published as replaceable txs, without claiming their outputs
|
||||||
val htlcTxs = localCommitPublished.htlcTxs.values.collect { case Some(tx: HtlcTx) => tx }
|
val htlcTxs = localCommitPublished.htlcTxs.values.collect { case Some(tx: HtlcTx) => tx }
|
||||||
val publishedTxs = htlcTxs.map(_ => s2blockchain.expectMsgType[TxPublisher.PublishReplaceableTx])
|
val publishedTxs = htlcTxs.map(_ => s2blockchain.expectMsgType[TxPublisher.PublishReplaceableTx])
|
||||||
|
@ -629,7 +629,7 @@ trait ChannelStateTestsBase extends Assertions with Eventually {
|
||||||
|
|
||||||
// If anchor outputs is used, we use the anchor output to bump the fees if necessary.
|
// If anchor outputs is used, we use the anchor output to bump the fees if necessary.
|
||||||
closingData.commitments.params.commitmentFormat match {
|
closingData.commitments.params.commitmentFormat match {
|
||||||
case _: AnchorOutputsCommitmentFormat =>
|
case _: AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat =>
|
||||||
val anchorTx = s2blockchain.expectMsgType[PublishReplaceableTx]
|
val anchorTx = s2blockchain.expectMsgType[PublishReplaceableTx]
|
||||||
assert(anchorTx.txInfo.isInstanceOf[ClaimLocalAnchorOutputTx])
|
assert(anchorTx.txInfo.isInstanceOf[ClaimLocalAnchorOutputTx])
|
||||||
case Transactions.DefaultCommitmentFormat => ()
|
case Transactions.DefaultCommitmentFormat => ()
|
||||||
|
|
|
@ -55,7 +55,7 @@ class WaitForDualFundingSignedStateSpec extends TestKitBaseClass with FixtureAny
|
||||||
val (initiatorPushAmount, nonInitiatorPushAmount) = if (test.tags.contains("both_push_amount")) (Some(TestConstants.initiatorPushAmount), Some(TestConstants.nonInitiatorPushAmount)) else (None, None)
|
val (initiatorPushAmount, nonInitiatorPushAmount) = if (test.tags.contains("both_push_amount")) (Some(TestConstants.initiatorPushAmount), Some(TestConstants.nonInitiatorPushAmount)) else (None, None)
|
||||||
val commitFeerate = channelType.commitmentFormat match {
|
val commitFeerate = channelType.commitmentFormat match {
|
||||||
case Transactions.DefaultCommitmentFormat => TestConstants.feeratePerKw
|
case Transactions.DefaultCommitmentFormat => TestConstants.feeratePerKw
|
||||||
case _: Transactions.AnchorOutputsCommitmentFormat => TestConstants.anchorOutputsFeeratePerKw
|
case _: Transactions.AnchorOutputsCommitmentFormat | Transactions.SimpleTaprootChannelCommitmentFormat => TestConstants.anchorOutputsFeeratePerKw
|
||||||
}
|
}
|
||||||
val aliceListener = TestProbe()
|
val aliceListener = TestProbe()
|
||||||
val bobListener = TestProbe()
|
val bobListener = TestProbe()
|
||||||
|
|
|
@ -61,7 +61,7 @@ class WaitForFundingSignedStateSpec extends TestKitBaseClass with FixtureAnyFunS
|
||||||
val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags)
|
val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags)
|
||||||
val commitFeerate = channelType.commitmentFormat match {
|
val commitFeerate = channelType.commitmentFormat match {
|
||||||
case Transactions.DefaultCommitmentFormat => TestConstants.feeratePerKw
|
case Transactions.DefaultCommitmentFormat => TestConstants.feeratePerKw
|
||||||
case _: Transactions.AnchorOutputsCommitmentFormat => TestConstants.anchorOutputsFeeratePerKw
|
case _: Transactions.AnchorOutputsCommitmentFormat | Transactions.SimpleTaprootChannelCommitmentFormat => TestConstants.anchorOutputsFeeratePerKw
|
||||||
}
|
}
|
||||||
val aliceInit = Init(aliceParams.initFeatures)
|
val aliceInit = Init(aliceParams.initFeatures)
|
||||||
val bobInit = Init(bobParams.initFeatures)
|
val bobInit = Init(bobParams.initFeatures)
|
||||||
|
|
|
@ -53,7 +53,7 @@ class WaitForChannelReadyStateSpec extends TestKitBaseClass with FixtureAnyFunSu
|
||||||
val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags)
|
val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags)
|
||||||
val commitFeerate = channelType.commitmentFormat match {
|
val commitFeerate = channelType.commitmentFormat match {
|
||||||
case Transactions.DefaultCommitmentFormat => TestConstants.feeratePerKw
|
case Transactions.DefaultCommitmentFormat => TestConstants.feeratePerKw
|
||||||
case _: Transactions.AnchorOutputsCommitmentFormat => TestConstants.anchorOutputsFeeratePerKw
|
case _: Transactions.AnchorOutputsCommitmentFormat | Transactions.SimpleTaprootChannelCommitmentFormat => TestConstants.anchorOutputsFeeratePerKw
|
||||||
}
|
}
|
||||||
val pushMsat = if (test.tags.contains(ChannelStateTestsTags.NoPushAmount)) None else Some(TestConstants.initiatorPushAmount)
|
val pushMsat = if (test.tags.contains(ChannelStateTestsTags.NoPushAmount)) None else Some(TestConstants.initiatorPushAmount)
|
||||||
val aliceInit = Init(aliceParams.initFeatures)
|
val aliceInit = Init(aliceParams.initFeatures)
|
||||||
|
|
|
@ -72,7 +72,7 @@ class WaitForDualFundingConfirmedStateSpec extends TestKitBaseClass with Fixture
|
||||||
val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags)
|
val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags)
|
||||||
val commitFeerate = channelType.commitmentFormat match {
|
val commitFeerate = channelType.commitmentFormat match {
|
||||||
case Transactions.DefaultCommitmentFormat => TestConstants.feeratePerKw
|
case Transactions.DefaultCommitmentFormat => TestConstants.feeratePerKw
|
||||||
case _: Transactions.AnchorOutputsCommitmentFormat => TestConstants.anchorOutputsFeeratePerKw
|
case _: Transactions.AnchorOutputsCommitmentFormat | Transactions.SimpleTaprootChannelCommitmentFormat => TestConstants.anchorOutputsFeeratePerKw
|
||||||
}
|
}
|
||||||
val aliceInit = Init(aliceParams.initFeatures)
|
val aliceInit = Init(aliceParams.initFeatures)
|
||||||
val bobInit = Init(bobParams.initFeatures)
|
val bobInit = Init(bobParams.initFeatures)
|
||||||
|
|
|
@ -990,7 +990,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with
|
||||||
// Bob publishes the latest commit tx.
|
// Bob publishes the latest commit tx.
|
||||||
val bobCommitTx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localCommit.commitTxAndRemoteSig.commitTx.tx
|
val bobCommitTx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localCommit.commitTxAndRemoteSig.commitTx.tx
|
||||||
channelFeatures.commitmentFormat match {
|
channelFeatures.commitmentFormat match {
|
||||||
case _: AnchorOutputsCommitmentFormat => assert(bobCommitTx.txOut.length == 7) // two main outputs + two anchors + 3 HTLCs
|
case _: AnchorOutputsCommitmentFormat | Transactions.SimpleTaprootChannelCommitmentFormat => assert(bobCommitTx.txOut.length == 7) // two main outputs + two anchors + 3 HTLCs
|
||||||
case DefaultCommitmentFormat => assert(bobCommitTx.txOut.length == 5) // two main outputs + 3 HTLCs
|
case DefaultCommitmentFormat => assert(bobCommitTx.txOut.length == 5) // two main outputs + 3 HTLCs
|
||||||
}
|
}
|
||||||
val closingState = remoteClose(bobCommitTx, alice, alice2blockchain)
|
val closingState = remoteClose(bobCommitTx, alice, alice2blockchain)
|
||||||
|
@ -1124,7 +1124,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with
|
||||||
// Bob publishes the next commit tx.
|
// Bob publishes the next commit tx.
|
||||||
val bobCommitTx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localCommit.commitTxAndRemoteSig.commitTx.tx
|
val bobCommitTx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localCommit.commitTxAndRemoteSig.commitTx.tx
|
||||||
channelFeatures.commitmentFormat match {
|
channelFeatures.commitmentFormat match {
|
||||||
case _: AnchorOutputsCommitmentFormat => assert(bobCommitTx.txOut.length == 7) // two main outputs + two anchors + 3 HTLCs
|
case _: AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat => assert(bobCommitTx.txOut.length == 7) // two main outputs + two anchors + 3 HTLCs
|
||||||
case DefaultCommitmentFormat => assert(bobCommitTx.txOut.length == 5) // two main outputs + 3 HTLCs
|
case DefaultCommitmentFormat => assert(bobCommitTx.txOut.length == 5) // two main outputs + 3 HTLCs
|
||||||
}
|
}
|
||||||
val closingState = remoteClose(bobCommitTx, alice, alice2blockchain)
|
val closingState = remoteClose(bobCommitTx, alice, alice2blockchain)
|
||||||
|
@ -1319,7 +1319,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with
|
||||||
// bob is nice and publishes its commitment
|
// bob is nice and publishes its commitment
|
||||||
val bobCommitTx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localCommit.commitTxAndRemoteSig.commitTx.tx
|
val bobCommitTx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localCommit.commitTxAndRemoteSig.commitTx.tx
|
||||||
channelFeatures.commitmentFormat match {
|
channelFeatures.commitmentFormat match {
|
||||||
case _: AnchorOutputsCommitmentFormat => assert(bobCommitTx.txOut.length == 6) // two main outputs + two anchors + 2 HTLCs
|
case _: AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat => assert(bobCommitTx.txOut.length == 6) // two main outputs + two anchors + 2 HTLCs
|
||||||
case DefaultCommitmentFormat => assert(bobCommitTx.txOut.length == 4) // two main outputs + 2 HTLCs
|
case DefaultCommitmentFormat => assert(bobCommitTx.txOut.length == 4) // two main outputs + 2 HTLCs
|
||||||
}
|
}
|
||||||
alice ! WatchFundingSpentTriggered(bobCommitTx)
|
alice ! WatchFundingSpentTriggered(bobCommitTx)
|
||||||
|
@ -1393,7 +1393,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with
|
||||||
// Bob's first commit tx doesn't contain any htlc
|
// Bob's first commit tx doesn't contain any htlc
|
||||||
val localCommit1 = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localCommit
|
val localCommit1 = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localCommit
|
||||||
channelFeatures.commitmentFormat match {
|
channelFeatures.commitmentFormat match {
|
||||||
case _: AnchorOutputsCommitmentFormat => assert(localCommit1.commitTxAndRemoteSig.commitTx.tx.txOut.size == 4) // 2 main outputs + 2 anchors
|
case _: AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat => assert(localCommit1.commitTxAndRemoteSig.commitTx.tx.txOut.size == 4) // 2 main outputs + 2 anchors
|
||||||
case DefaultCommitmentFormat => assert(localCommit1.commitTxAndRemoteSig.commitTx.tx.txOut.size == 2) // 2 main outputs
|
case DefaultCommitmentFormat => assert(localCommit1.commitTxAndRemoteSig.commitTx.tx.txOut.size == 2) // 2 main outputs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1409,7 +1409,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with
|
||||||
|
|
||||||
assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localCommit.commitTxAndRemoteSig.commitTx.tx.txOut.size == localCommit2.commitTxAndRemoteSig.commitTx.tx.txOut.size)
|
assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localCommit.commitTxAndRemoteSig.commitTx.tx.txOut.size == localCommit2.commitTxAndRemoteSig.commitTx.tx.txOut.size)
|
||||||
channelFeatures.commitmentFormat match {
|
channelFeatures.commitmentFormat match {
|
||||||
case _: AnchorOutputsCommitmentFormat => assert(localCommit2.commitTxAndRemoteSig.commitTx.tx.txOut.size == 6)
|
case _: AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat => assert(localCommit2.commitTxAndRemoteSig.commitTx.tx.txOut.size == 6)
|
||||||
case DefaultCommitmentFormat => assert(localCommit2.commitTxAndRemoteSig.commitTx.tx.txOut.size == 4)
|
case DefaultCommitmentFormat => assert(localCommit2.commitTxAndRemoteSig.commitTx.tx.txOut.size == 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1425,7 +1425,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with
|
||||||
|
|
||||||
assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localCommit.commitTxAndRemoteSig.commitTx.tx.txOut.size == localCommit3.commitTxAndRemoteSig.commitTx.tx.txOut.size)
|
assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localCommit.commitTxAndRemoteSig.commitTx.tx.txOut.size == localCommit3.commitTxAndRemoteSig.commitTx.tx.txOut.size)
|
||||||
channelFeatures.commitmentFormat match {
|
channelFeatures.commitmentFormat match {
|
||||||
case _: AnchorOutputsCommitmentFormat => assert(localCommit3.commitTxAndRemoteSig.commitTx.tx.txOut.size == 8)
|
case _: AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat => assert(localCommit3.commitTxAndRemoteSig.commitTx.tx.txOut.size == 8)
|
||||||
case DefaultCommitmentFormat => assert(localCommit3.commitTxAndRemoteSig.commitTx.tx.txOut.size == 6)
|
case DefaultCommitmentFormat => assert(localCommit3.commitTxAndRemoteSig.commitTx.tx.txOut.size == 6)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1439,7 +1439,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with
|
||||||
|
|
||||||
assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localCommit.commitTxAndRemoteSig.commitTx.tx.txOut.size == localCommit4.commitTxAndRemoteSig.commitTx.tx.txOut.size)
|
assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localCommit.commitTxAndRemoteSig.commitTx.tx.txOut.size == localCommit4.commitTxAndRemoteSig.commitTx.tx.txOut.size)
|
||||||
channelFeatures.commitmentFormat match {
|
channelFeatures.commitmentFormat match {
|
||||||
case _: AnchorOutputsCommitmentFormat => assert(localCommit4.commitTxAndRemoteSig.commitTx.tx.txOut.size == 4)
|
case _: AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat => assert(localCommit4.commitTxAndRemoteSig.commitTx.tx.txOut.size == 4)
|
||||||
case DefaultCommitmentFormat => assert(localCommit4.commitTxAndRemoteSig.commitTx.tx.txOut.size == 2)
|
case DefaultCommitmentFormat => assert(localCommit4.commitTxAndRemoteSig.commitTx.tx.txOut.size == 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1820,7 +1820,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with
|
||||||
import f._
|
import f._
|
||||||
assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.params.channelFeatures == channelFeatures)
|
assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.params.channelFeatures == channelFeatures)
|
||||||
val initOutputCount = channelFeatures.commitmentFormat match {
|
val initOutputCount = channelFeatures.commitmentFormat match {
|
||||||
case _: AnchorOutputsCommitmentFormat => 4
|
case _: AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat => 4
|
||||||
case DefaultCommitmentFormat => 2
|
case DefaultCommitmentFormat => 2
|
||||||
}
|
}
|
||||||
assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localCommit.commitTxAndRemoteSig.commitTx.tx.txOut.size == initOutputCount)
|
assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localCommit.commitTxAndRemoteSig.commitTx.tx.txOut.size == initOutputCount)
|
||||||
|
|
|
@ -35,7 +35,7 @@ import fr.acinq.eclair.payment.receive.MultiPartHandler.ReceiveStandardPayment
|
||||||
import fr.acinq.eclair.payment.receive.{ForwardHandler, PaymentHandler}
|
import fr.acinq.eclair.payment.receive.{ForwardHandler, PaymentHandler}
|
||||||
import fr.acinq.eclair.payment.send.PaymentInitiator.SendPaymentToNode
|
import fr.acinq.eclair.payment.send.PaymentInitiator.SendPaymentToNode
|
||||||
import fr.acinq.eclair.router.Router
|
import fr.acinq.eclair.router.Router
|
||||||
import fr.acinq.eclair.transactions.Transactions.{AnchorOutputsCommitmentFormat, CommitmentFormat, DefaultCommitmentFormat, TxOwner}
|
import fr.acinq.eclair.transactions.Transactions.{AnchorOutputsCommitmentFormat, CommitmentFormat, DefaultCommitmentFormat, SimpleTaprootChannelCommitmentFormat, TxOwner}
|
||||||
import fr.acinq.eclair.transactions.{OutgoingHtlc, Scripts, Transactions}
|
import fr.acinq.eclair.transactions.{OutgoingHtlc, Scripts, Transactions}
|
||||||
import fr.acinq.eclair.wire.protocol._
|
import fr.acinq.eclair.wire.protocol._
|
||||||
import fr.acinq.eclair.{MilliSatoshi, MilliSatoshiLong, randomBytes32}
|
import fr.acinq.eclair.{MilliSatoshi, MilliSatoshiLong, randomBytes32}
|
||||||
|
@ -181,7 +181,7 @@ abstract class ChannelIntegrationSpec extends IntegrationSpec {
|
||||||
generateBlocks(25, Some(minerAddress))
|
generateBlocks(25, Some(minerAddress))
|
||||||
val expectedTxCountC = 1 // C should have 1 recv transaction: its main output
|
val expectedTxCountC = 1 // C should have 1 recv transaction: its main output
|
||||||
val expectedTxCountF = commitmentFormat match {
|
val expectedTxCountF = commitmentFormat match {
|
||||||
case _: AnchorOutputsCommitmentFormat => 2 // F should have 2 recv transactions: the redeemed htlc and its main output
|
case _: AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat => 2 // F should have 2 recv transactions: the redeemed htlc and its main output
|
||||||
case Transactions.DefaultCommitmentFormat => 1 // F's main output uses static_remotekey
|
case Transactions.DefaultCommitmentFormat => 1 // F's main output uses static_remotekey
|
||||||
}
|
}
|
||||||
awaitCond({
|
awaitCond({
|
||||||
|
@ -221,7 +221,7 @@ abstract class ChannelIntegrationSpec extends IntegrationSpec {
|
||||||
// we then generate enough blocks so that F gets its htlc-success delayed output
|
// we then generate enough blocks so that F gets its htlc-success delayed output
|
||||||
generateBlocks(25, Some(minerAddress))
|
generateBlocks(25, Some(minerAddress))
|
||||||
val expectedTxCountC = commitmentFormat match {
|
val expectedTxCountC = commitmentFormat match {
|
||||||
case _: AnchorOutputsCommitmentFormat => 1 // C should have 1 recv transaction: its main output
|
case _: AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat => 1 // C should have 1 recv transaction: its main output
|
||||||
case Transactions.DefaultCommitmentFormat => 0 // C's main output uses static_remotekey
|
case Transactions.DefaultCommitmentFormat => 0 // C's main output uses static_remotekey
|
||||||
}
|
}
|
||||||
val expectedTxCountF = 2 // F should have 2 recv transactions: the redeemed htlc and its main output
|
val expectedTxCountF = 2 // F should have 2 recv transactions: the redeemed htlc and its main output
|
||||||
|
@ -275,7 +275,7 @@ abstract class ChannelIntegrationSpec extends IntegrationSpec {
|
||||||
generateBlocks(25, Some(minerAddress))
|
generateBlocks(25, Some(minerAddress))
|
||||||
val expectedTxCountC = 2 // C should have 2 recv transactions: its main output and the htlc timeout
|
val expectedTxCountC = 2 // C should have 2 recv transactions: its main output and the htlc timeout
|
||||||
val expectedTxCountF = commitmentFormat match {
|
val expectedTxCountF = commitmentFormat match {
|
||||||
case _: AnchorOutputsCommitmentFormat => 1 // F should have 1 recv transaction: its main output
|
case _: AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat => 1 // F should have 1 recv transaction: its main output
|
||||||
case Transactions.DefaultCommitmentFormat => 0 // F's main output uses static_remotekey
|
case Transactions.DefaultCommitmentFormat => 0 // F's main output uses static_remotekey
|
||||||
}
|
}
|
||||||
awaitCond({
|
awaitCond({
|
||||||
|
@ -330,7 +330,7 @@ abstract class ChannelIntegrationSpec extends IntegrationSpec {
|
||||||
// we then generate enough blocks to confirm all delayed transactions
|
// we then generate enough blocks to confirm all delayed transactions
|
||||||
generateBlocks(25, Some(minerAddress))
|
generateBlocks(25, Some(minerAddress))
|
||||||
val expectedTxCountC = commitmentFormat match {
|
val expectedTxCountC = commitmentFormat match {
|
||||||
case _: AnchorOutputsCommitmentFormat => 2 // C should have 2 recv transactions: its main output and the htlc timeout
|
case _: AnchorOutputsCommitmentFormat | SimpleTaprootChannelCommitmentFormat => 2 // C should have 2 recv transactions: its main output and the htlc timeout
|
||||||
case Transactions.DefaultCommitmentFormat => 1 // C's main output uses static_remotekey
|
case Transactions.DefaultCommitmentFormat => 1 // C's main output uses static_remotekey
|
||||||
}
|
}
|
||||||
val expectedTxCountF = 1 // F should have 1 recv transaction: its main output
|
val expectedTxCountF = 1 // F should have 1 recv transaction: its main output
|
||||||
|
@ -405,7 +405,7 @@ abstract class ChannelIntegrationSpec extends IntegrationSpec {
|
||||||
val localCommitF = commitmentsF.latest.localCommit
|
val localCommitF = commitmentsF.latest.localCommit
|
||||||
commitmentFormat match {
|
commitmentFormat match {
|
||||||
case Transactions.DefaultCommitmentFormat => assert(localCommitF.commitTxAndRemoteSig.commitTx.tx.txOut.size == 6)
|
case Transactions.DefaultCommitmentFormat => assert(localCommitF.commitTxAndRemoteSig.commitTx.tx.txOut.size == 6)
|
||||||
case _: Transactions.AnchorOutputsCommitmentFormat => assert(localCommitF.commitTxAndRemoteSig.commitTx.tx.txOut.size == 8)
|
case _: Transactions.AnchorOutputsCommitmentFormat | Transactions.SimpleTaprootChannelCommitmentFormat => assert(localCommitF.commitTxAndRemoteSig.commitTx.tx.txOut.size == 8)
|
||||||
}
|
}
|
||||||
val outgoingHtlcExpiry = localCommitF.spec.htlcs.collect { case OutgoingHtlc(add) => add.cltvExpiry }.max
|
val outgoingHtlcExpiry = localCommitF.spec.htlcs.collect { case OutgoingHtlc(add) => add.cltvExpiry }.max
|
||||||
val htlcTimeoutTxs = localCommitF.htlcTxsAndRemoteSigs.collect { case h@HtlcTxAndRemoteSig(_: Transactions.HtlcTimeoutTx, _) => h }
|
val htlcTimeoutTxs = localCommitF.htlcTxsAndRemoteSigs.collect { case h@HtlcTxAndRemoteSig(_: Transactions.HtlcTimeoutTx, _) => h }
|
||||||
|
|
|
@ -770,14 +770,15 @@ class TransactionsSpec extends AnyFunSuite with Logging {
|
||||||
val commitTxNumber = 0x404142434445L
|
val commitTxNumber = 0x404142434445L
|
||||||
val outputs = makeCommitTxOutputs(localPaysCommitTxFees = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, spec, commitmentFormat)
|
val outputs = makeCommitTxOutputs(localPaysCommitTxFees = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, spec, commitmentFormat)
|
||||||
val txInfo = makeCommitTx(commitInput, commitTxNumber, localPaymentPriv.publicKey, remotePaymentPriv.publicKey, localIsChannelOpener = true, outputs)
|
val txInfo = makeCommitTx(commitInput, commitTxNumber, localPaymentPriv.publicKey, remotePaymentPriv.publicKey, localIsChannelOpener = true, outputs)
|
||||||
val commitTx = if (commitmentFormat.useTaproot) {
|
val commitTx = commitmentFormat match {
|
||||||
|
case SimpleTaprootChannelCommitmentFormat =>
|
||||||
val Right(sig) = for {
|
val Right(sig) = for {
|
||||||
localPartialSig <- Musig2.signTaprootInput(localFundingPriv, txInfo.tx, 0, Seq(fundingOutput), publicKeys, secretLocalNonce, publicNonces, None)
|
localPartialSig <- Musig2.signTaprootInput(localFundingPriv, txInfo.tx, 0, Seq(fundingOutput), publicKeys, secretLocalNonce, publicNonces, None)
|
||||||
remotePartialSig <- Musig2.signTaprootInput(remoteFundingPriv, txInfo.tx, 0, Seq(fundingOutput), publicKeys, secretRemoteNonce, publicNonces, None)
|
remotePartialSig <- Musig2.signTaprootInput(remoteFundingPriv, txInfo.tx, 0, Seq(fundingOutput), publicKeys, secretRemoteNonce, publicNonces, None)
|
||||||
sig <- Musig2.aggregateTaprootSignatures(Seq(localPartialSig, remotePartialSig), txInfo.tx, 0, Seq(fundingOutput), publicKeys, publicNonces, None)
|
sig <- Musig2.aggregateTaprootSignatures(Seq(localPartialSig, remotePartialSig), txInfo.tx, 0, Seq(fundingOutput), publicKeys, publicNonces, None)
|
||||||
} yield sig
|
} yield sig
|
||||||
Transactions.addAggregatedSignature(txInfo, sig)
|
Transactions.addAggregatedSignature(txInfo, sig)
|
||||||
} else {
|
case _ =>
|
||||||
val localSig = txInfo.sign(localPaymentPriv, TxOwner.Local, commitmentFormat)
|
val localSig = txInfo.sign(localPaymentPriv, TxOwner.Local, commitmentFormat)
|
||||||
val remoteSig = txInfo.sign(remotePaymentPriv, TxOwner.Remote, commitmentFormat)
|
val remoteSig = txInfo.sign(remotePaymentPriv, TxOwner.Remote, commitmentFormat)
|
||||||
Transactions.addSigs(txInfo, localFundingPriv.publicKey, remoteFundingPriv.publicKey, localSig, remoteSig)
|
Transactions.addSigs(txInfo, localFundingPriv.publicKey, remoteFundingPriv.publicKey, localSig, remoteSig)
|
||||||
|
@ -815,10 +816,9 @@ class TransactionsSpec extends AnyFunSuite with Logging {
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// local spends local anchor
|
// local spends local anchor
|
||||||
val anchorKey = if (commitmentFormat.useTaproot) {
|
val anchorKey = commitmentFormat match {
|
||||||
localDelayedPaymentPriv
|
case SimpleTaprootChannelCommitmentFormat => localDelayedPaymentPriv
|
||||||
} else {
|
case _ => localFundingPriv
|
||||||
localFundingPriv
|
|
||||||
}
|
}
|
||||||
val Right(claimAnchorOutputTx) = makeClaimLocalAnchorOutputTx(commitTx.tx, anchorKey.publicKey, ConfirmationTarget.Absolute(BlockHeight(0)))
|
val Right(claimAnchorOutputTx) = makeClaimLocalAnchorOutputTx(commitTx.tx, anchorKey.publicKey, ConfirmationTarget.Absolute(BlockHeight(0)))
|
||||||
assert(checkSpendable(claimAnchorOutputTx).isFailure)
|
assert(checkSpendable(claimAnchorOutputTx).isFailure)
|
||||||
|
@ -828,10 +828,9 @@ class TransactionsSpec extends AnyFunSuite with Logging {
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// remote spends remote anchor
|
// remote spends remote anchor
|
||||||
val anchorKey = if (commitmentFormat.useTaproot) {
|
val anchorKey = commitmentFormat match {
|
||||||
remotePaymentPriv
|
case SimpleTaprootChannelCommitmentFormat => remotePaymentPriv
|
||||||
} else {
|
case _ => remoteFundingPriv
|
||||||
remoteFundingPriv
|
|
||||||
}
|
}
|
||||||
val Right(claimAnchorOutputTx) = makeClaimLocalAnchorOutputTx(commitTx.tx, anchorKey.publicKey, ConfirmationTarget.Absolute(BlockHeight(0)))
|
val Right(claimAnchorOutputTx) = makeClaimLocalAnchorOutputTx(commitTx.tx, anchorKey.publicKey, ConfirmationTarget.Absolute(BlockHeight(0)))
|
||||||
assert(checkSpendable(claimAnchorOutputTx).isFailure)
|
assert(checkSpendable(claimAnchorOutputTx).isFailure)
|
||||||
|
@ -950,10 +949,11 @@ class TransactionsSpec extends AnyFunSuite with Logging {
|
||||||
val Some(htlcOutputIndex) = commitTxOutputs.map(_.filter[OutHtlc]).zipWithIndex.collectFirst {
|
val Some(htlcOutputIndex) = commitTxOutputs.map(_.filter[OutHtlc]).zipWithIndex.collectFirst {
|
||||||
case (Some(co), outputIndex) if co.commitmentOutput.outgoingHtlc.add.id == htlc1.id => outputIndex
|
case (Some(co), outputIndex) if co.commitmentOutput.outgoingHtlc.add.id == htlc1.id => outputIndex
|
||||||
}
|
}
|
||||||
val Right(htlcPenaltyTx) = if (commitmentFormat.useTaproot) {
|
val Right(htlcPenaltyTx) = commitmentFormat match {
|
||||||
|
case SimpleTaprootChannelCommitmentFormat =>
|
||||||
val scriptTree = Taproot.offeredHtlcScriptTree(localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, htlc1.paymentHash)
|
val scriptTree = Taproot.offeredHtlcScriptTree(localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, htlc1.paymentHash)
|
||||||
makeHtlcPenaltyTx(commitTx.tx, htlcOutputIndex, localRevocationPriv.publicKey.xOnly, Some(scriptTree), localDustLimit, finalPubKeyScript, feeratePerKw)
|
makeHtlcPenaltyTx(commitTx.tx, htlcOutputIndex, localRevocationPriv.publicKey.xOnly, Some(scriptTree), localDustLimit, finalPubKeyScript, feeratePerKw)
|
||||||
} else {
|
case _ =>
|
||||||
val script = Script.write(Scripts.htlcOffered(localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localRevocationPriv.publicKey, Crypto.ripemd160(htlc1.paymentHash), commitmentFormat))
|
val script = Script.write(Scripts.htlcOffered(localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localRevocationPriv.publicKey, Crypto.ripemd160(htlc1.paymentHash), commitmentFormat))
|
||||||
makeHtlcPenaltyTx(commitTx.tx, htlcOutputIndex, script, localDustLimit, finalPubKeyScript, feeratePerKw)
|
makeHtlcPenaltyTx(commitTx.tx, htlcOutputIndex, script, localDustLimit, finalPubKeyScript, feeratePerKw)
|
||||||
}
|
}
|
||||||
|
@ -967,10 +967,11 @@ class TransactionsSpec extends AnyFunSuite with Logging {
|
||||||
val Some(htlcOutputIndex) = commitTxOutputs.map(_.filter[InHtlc]).zipWithIndex.collectFirst {
|
val Some(htlcOutputIndex) = commitTxOutputs.map(_.filter[InHtlc]).zipWithIndex.collectFirst {
|
||||||
case (Some(co), outputIndex) if co.commitmentOutput.incomingHtlc.add.id == htlc.id => outputIndex
|
case (Some(co), outputIndex) if co.commitmentOutput.incomingHtlc.add.id == htlc.id => outputIndex
|
||||||
}
|
}
|
||||||
val Right(htlcPenaltyTx) = if (commitmentFormat.useTaproot) {
|
val Right(htlcPenaltyTx) = commitmentFormat match {
|
||||||
|
case SimpleTaprootChannelCommitmentFormat =>
|
||||||
val scriptTree = Taproot.receivedHtlcScriptTree(localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, htlc.paymentHash, htlc.cltvExpiry)
|
val scriptTree = Taproot.receivedHtlcScriptTree(localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, htlc.paymentHash, htlc.cltvExpiry)
|
||||||
makeHtlcPenaltyTx(commitTx.tx, htlcOutputIndex, localRevocationPriv.publicKey.xOnly, Some(scriptTree), localDustLimit, finalPubKeyScript, feeratePerKw)
|
makeHtlcPenaltyTx(commitTx.tx, htlcOutputIndex, localRevocationPriv.publicKey.xOnly, Some(scriptTree), localDustLimit, finalPubKeyScript, feeratePerKw)
|
||||||
} else {
|
case _ =>
|
||||||
val script = Script.write(Scripts.htlcReceived(localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localRevocationPriv.publicKey, Crypto.ripemd160(htlc.paymentHash), htlc.cltvExpiry, commitmentFormat))
|
val script = Script.write(Scripts.htlcReceived(localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localRevocationPriv.publicKey, Crypto.ripemd160(htlc.paymentHash), htlc.cltvExpiry, commitmentFormat))
|
||||||
makeHtlcPenaltyTx(commitTx.tx, htlcOutputIndex, script, localDustLimit, finalPubKeyScript, feeratePerKw)
|
makeHtlcPenaltyTx(commitTx.tx, htlcOutputIndex, script, localDustLimit, finalPubKeyScript, feeratePerKw)
|
||||||
}
|
}
|
||||||
|
@ -1120,9 +1121,8 @@ class TransactionsSpec extends AnyFunSuite with Logging {
|
||||||
txOut = TxOut(25_000.sat, Taproot.htlcDelayed(localDelayedPaymentPriv.publicKey, toLocalDelay, localRevocationPriv.publicKey)) :: Nil,
|
txOut = TxOut(25_000.sat, Taproot.htlcDelayed(localDelayedPaymentPriv.publicKey, toLocalDelay, localRevocationPriv.publicKey)) :: Nil,
|
||||||
lockTime = 300)
|
lockTime = 300)
|
||||||
val scriptTree = Taproot.offeredHtlcScriptTree(localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, paymentHash)
|
val scriptTree = Taproot.offeredHtlcScriptTree(localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, paymentHash)
|
||||||
val sigHash = SigHash.SIGHASH_SINGLE | SigHash.SIGHASH_ANYONECANPAY
|
val localSig = Taproot.encodeSig(Transaction.signInputTaprootScriptPath(localHtlcPriv, tx, 0, Seq(commitTx.txOut(4)), SigHash.SIGHASH_SINGLE | SigHash.SIGHASH_ANYONECANPAY, scriptTree.getLeft.hash()), SigHash.SIGHASH_SINGLE | SigHash.SIGHASH_ANYONECANPAY)
|
||||||
val localSig = Taproot.encodeSig(Transaction.signInputTaprootScriptPath(localHtlcPriv, tx, 0, Seq(commitTx.txOut(4)), sigHash, scriptTree.getLeft.hash()), sigHash)
|
val remoteSig = Taproot.encodeSig(Transaction.signInputTaprootScriptPath(remoteHtlcPriv, tx, 0, Seq(commitTx.txOut(4)), SigHash.SIGHASH_DEFAULT, scriptTree.getLeft.hash()), SigHash.SIGHASH_DEFAULT)
|
||||||
val remoteSig = Taproot.encodeSig(Transaction.signInputTaprootScriptPath(remoteHtlcPriv, tx, 0, Seq(commitTx.txOut(4)), sigHash, scriptTree.getLeft.hash()), sigHash)
|
|
||||||
val witness = Script.witnessScriptPathPay2tr(localRevocationPriv.xOnlyPublicKey(), scriptTree.getLeft.asInstanceOf[ScriptTree.Leaf], ScriptWitness(Seq(remoteSig, localSig)), scriptTree)
|
val witness = Script.witnessScriptPathPay2tr(localRevocationPriv.xOnlyPublicKey(), scriptTree.getLeft.asInstanceOf[ScriptTree.Leaf], ScriptWitness(Seq(remoteSig, localSig)), scriptTree)
|
||||||
tx.updateWitness(0, witness)
|
tx.updateWitness(0, witness)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue