1616
1717package fr .acinq .eclair .transactions
1818
19- import fr .acinq .bitcoin .ScriptFlags
19+ import fr .acinq .bitcoin .{ ScriptFlags , ScriptTree }
2020import fr .acinq .bitcoin .SigHash ._
2121import fr .acinq .bitcoin .SigVersion ._
22- import fr .acinq .bitcoin .scalacompat .Crypto .{PrivateKey , PublicKey , ripemd160 }
22+ import fr .acinq .bitcoin .scalacompat .Crypto .{PrivateKey , PublicKey , XonlyPublicKey , ripemd160 }
2323import fr .acinq .bitcoin .scalacompat .Script ._
2424import fr .acinq .bitcoin .scalacompat ._
2525import fr .acinq .eclair ._
@@ -94,9 +94,22 @@ object Transactions {
9494
9595 // @formatter:off
9696 case class OutputInfo (index : Long , amount : Satoshi , publicKeyScript : ByteVector )
97- case class InputInfo (outPoint : OutPoint , txOut : TxOut , redeemScript : ByteVector )
97+
98+ /**
99+ * to spend the output of a taproot transactions, we need to know the script tree and internal key used to build this output
100+ */
101+ case class ScriptTreeAndInternalKey (scriptTree : ScriptTree , internalKey : XonlyPublicKey ) {
102+ val publicKeyScript : ByteVector = Script .write(Script .pay2tr(internalKey, Some (scriptTree)))
103+ }
104+
105+ case class InputInfo (outPoint : OutPoint , txOut : TxOut , redeemScriptOrScriptTree : Either [ByteVector , ScriptTreeAndInternalKey ]) {
106+ val redeemScriptOrEmptyScript : ByteVector = redeemScriptOrScriptTree.swap.getOrElse(ByteVector .empty) // TODO: use the actual script tree for taproot transactions, once we implement them
107+ }
108+
98109 object InputInfo {
99- def apply (outPoint : OutPoint , txOut : TxOut , redeemScript : Seq [ScriptElt ]) = new InputInfo (outPoint, txOut, Script .write(redeemScript))
110+ def apply (outPoint : OutPoint , txOut : TxOut , redeemScript : ByteVector ) = new InputInfo (outPoint, txOut, Left (redeemScript))
111+ def apply (outPoint : OutPoint , txOut : TxOut , redeemScript : Seq [ScriptElt ]) = new InputInfo (outPoint, txOut, Left (Script .write(redeemScript)))
112+ def apply (outPoint : OutPoint , txOut : TxOut , scriptTree : ScriptTreeAndInternalKey ) = new InputInfo (outPoint, txOut, Right (scriptTree))
100113 }
101114
102115 /** Owner of a given transaction (local/remote). */
@@ -125,12 +138,12 @@ object Transactions {
125138 // NB: the tx may have multiple inputs, we will only sign the one provided in txinfo.input. Bear in mind that the
126139 // signature will be invalidated if other inputs are added *afterwards* and sighashType was SIGHASH_ALL.
127140 val inputIndex = tx.txIn.zipWithIndex.find(_._1.outPoint == input.outPoint).get._2
128- Transactions .sign(tx, input.redeemScript , input.txOut.amount, key, sighashType, inputIndex)
141+ Transactions .sign(tx, input.redeemScriptOrEmptyScript , input.txOut.amount, key, sighashType, inputIndex)
129142 }
130143
131144 def checkSig (sig : ByteVector64 , pubKey : PublicKey , txOwner : TxOwner , commitmentFormat : CommitmentFormat ): Boolean = {
132145 val sighash = this .sighash(txOwner, commitmentFormat)
133- val data = Transaction .hashForSigning(tx, inputIndex = 0 , input.redeemScript , sighash, input.txOut.amount, SIGVERSION_WITNESS_V0 )
146+ val data = Transaction .hashForSigning(tx, inputIndex = 0 , input.redeemScriptOrEmptyScript , sighash, input.txOut.amount, SIGVERSION_WITNESS_V0 )
134147 Crypto .verifySignature(data, sig, pubKey)
135148 }
136149 }
@@ -964,7 +977,7 @@ object Transactions {
964977 // NB: the tx may have multiple inputs, we will only sign the one provided in txinfo.input. Bear in mind that the
965978 // signature will be invalidated if other inputs are added *afterwards* and sighashType was SIGHASH_ALL.
966979 val inputIndex = txinfo.tx.txIn.zipWithIndex.find(_._1.outPoint == txinfo.input.outPoint).get._2
967- sign(txinfo.tx, txinfo.input.redeemScript , txinfo.input.txOut.amount, key, sighashType, inputIndex)
980+ sign(txinfo.tx, txinfo.input.redeemScriptOrEmptyScript , txinfo.input.txOut.amount, key, sighashType, inputIndex)
968981 }
969982
970983 def addSigs (commitTx : CommitTx , localFundingPubkey : PublicKey , remoteFundingPubkey : PublicKey , localSig : ByteVector64 , remoteSig : ByteVector64 ): CommitTx = {
@@ -973,32 +986,32 @@ object Transactions {
973986 }
974987
975988 def addSigs (mainPenaltyTx : MainPenaltyTx , revocationSig : ByteVector64 ): MainPenaltyTx = {
976- val witness = Scripts .witnessToLocalDelayedWithRevocationSig(revocationSig, mainPenaltyTx.input.redeemScript )
989+ val witness = Scripts .witnessToLocalDelayedWithRevocationSig(revocationSig, mainPenaltyTx.input.redeemScriptOrEmptyScript )
977990 mainPenaltyTx.copy(tx = mainPenaltyTx.tx.updateWitness(0 , witness))
978991 }
979992
980993 def addSigs (htlcPenaltyTx : HtlcPenaltyTx , revocationSig : ByteVector64 , revocationPubkey : PublicKey ): HtlcPenaltyTx = {
981- val witness = Scripts .witnessHtlcWithRevocationSig(revocationSig, revocationPubkey, htlcPenaltyTx.input.redeemScript )
994+ val witness = Scripts .witnessHtlcWithRevocationSig(revocationSig, revocationPubkey, htlcPenaltyTx.input.redeemScriptOrEmptyScript )
982995 htlcPenaltyTx.copy(tx = htlcPenaltyTx.tx.updateWitness(0 , witness))
983996 }
984997
985998 def addSigs (htlcSuccessTx : HtlcSuccessTx , localSig : ByteVector64 , remoteSig : ByteVector64 , paymentPreimage : ByteVector32 , commitmentFormat : CommitmentFormat ): HtlcSuccessTx = {
986- val witness = witnessHtlcSuccess(localSig, remoteSig, paymentPreimage, htlcSuccessTx.input.redeemScript , commitmentFormat)
999+ val witness = witnessHtlcSuccess(localSig, remoteSig, paymentPreimage, htlcSuccessTx.input.redeemScriptOrEmptyScript , commitmentFormat)
9871000 htlcSuccessTx.copy(tx = htlcSuccessTx.tx.updateWitness(0 , witness))
9881001 }
9891002
9901003 def addSigs (htlcTimeoutTx : HtlcTimeoutTx , localSig : ByteVector64 , remoteSig : ByteVector64 , commitmentFormat : CommitmentFormat ): HtlcTimeoutTx = {
991- val witness = witnessHtlcTimeout(localSig, remoteSig, htlcTimeoutTx.input.redeemScript , commitmentFormat)
1004+ val witness = witnessHtlcTimeout(localSig, remoteSig, htlcTimeoutTx.input.redeemScriptOrEmptyScript , commitmentFormat)
9921005 htlcTimeoutTx.copy(tx = htlcTimeoutTx.tx.updateWitness(0 , witness))
9931006 }
9941007
9951008 def addSigs (claimHtlcSuccessTx : ClaimHtlcSuccessTx , localSig : ByteVector64 , paymentPreimage : ByteVector32 ): ClaimHtlcSuccessTx = {
996- val witness = witnessClaimHtlcSuccessFromCommitTx(localSig, paymentPreimage, claimHtlcSuccessTx.input.redeemScript )
1009+ val witness = witnessClaimHtlcSuccessFromCommitTx(localSig, paymentPreimage, claimHtlcSuccessTx.input.redeemScriptOrEmptyScript )
9971010 claimHtlcSuccessTx.copy(tx = claimHtlcSuccessTx.tx.updateWitness(0 , witness))
9981011 }
9991012
10001013 def addSigs (claimHtlcTimeoutTx : ClaimHtlcTimeoutTx , localSig : ByteVector64 ): ClaimHtlcTimeoutTx = {
1001- val witness = witnessClaimHtlcTimeoutFromCommitTx(localSig, claimHtlcTimeoutTx.input.redeemScript )
1014+ val witness = witnessClaimHtlcTimeoutFromCommitTx(localSig, claimHtlcTimeoutTx.input.redeemScriptOrEmptyScript )
10021015 claimHtlcTimeoutTx.copy(tx = claimHtlcTimeoutTx.tx.updateWitness(0 , witness))
10031016 }
10041017
@@ -1008,27 +1021,27 @@ object Transactions {
10081021 }
10091022
10101023 def addSigs (claimRemoteDelayedOutputTx : ClaimRemoteDelayedOutputTx , localSig : ByteVector64 ): ClaimRemoteDelayedOutputTx = {
1011- val witness = witnessClaimToRemoteDelayedFromCommitTx(localSig, claimRemoteDelayedOutputTx.input.redeemScript )
1024+ val witness = witnessClaimToRemoteDelayedFromCommitTx(localSig, claimRemoteDelayedOutputTx.input.redeemScriptOrEmptyScript )
10121025 claimRemoteDelayedOutputTx.copy(tx = claimRemoteDelayedOutputTx.tx.updateWitness(0 , witness))
10131026 }
10141027
10151028 def addSigs (claimDelayedOutputTx : ClaimLocalDelayedOutputTx , localSig : ByteVector64 ): ClaimLocalDelayedOutputTx = {
1016- val witness = witnessToLocalDelayedAfterDelay(localSig, claimDelayedOutputTx.input.redeemScript )
1029+ val witness = witnessToLocalDelayedAfterDelay(localSig, claimDelayedOutputTx.input.redeemScriptOrEmptyScript )
10171030 claimDelayedOutputTx.copy(tx = claimDelayedOutputTx.tx.updateWitness(0 , witness))
10181031 }
10191032
10201033 def addSigs (htlcDelayedTx : HtlcDelayedTx , localSig : ByteVector64 ): HtlcDelayedTx = {
1021- val witness = witnessToLocalDelayedAfterDelay(localSig, htlcDelayedTx.input.redeemScript )
1034+ val witness = witnessToLocalDelayedAfterDelay(localSig, htlcDelayedTx.input.redeemScriptOrEmptyScript )
10221035 htlcDelayedTx.copy(tx = htlcDelayedTx.tx.updateWitness(0 , witness))
10231036 }
10241037
10251038 def addSigs (claimAnchorOutputTx : ClaimLocalAnchorOutputTx , localSig : ByteVector64 ): ClaimLocalAnchorOutputTx = {
1026- val witness = witnessAnchor(localSig, claimAnchorOutputTx.input.redeemScript )
1039+ val witness = witnessAnchor(localSig, claimAnchorOutputTx.input.redeemScriptOrEmptyScript )
10271040 claimAnchorOutputTx.copy(tx = claimAnchorOutputTx.tx.updateWitness(0 , witness))
10281041 }
10291042
10301043 def addSigs (claimHtlcDelayedPenalty : ClaimHtlcDelayedOutputPenaltyTx , revocationSig : ByteVector64 ): ClaimHtlcDelayedOutputPenaltyTx = {
1031- val witness = Scripts .witnessToLocalDelayedWithRevocationSig(revocationSig, claimHtlcDelayedPenalty.input.redeemScript )
1044+ val witness = Scripts .witnessToLocalDelayedWithRevocationSig(revocationSig, claimHtlcDelayedPenalty.input.redeemScriptOrEmptyScript )
10321045 claimHtlcDelayedPenalty.copy(tx = claimHtlcDelayedPenalty.tx.updateWitness(0 , witness))
10331046 }
10341047
0 commit comments