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 }
@@ -872,7 +885,7 @@ object Transactions {
872885 // NB: the tx may have multiple inputs, we will only sign the one provided in txinfo.input. Bear in mind that the
873886 // signature will be invalidated if other inputs are added *afterwards* and sighashType was SIGHASH_ALL.
874887 val inputIndex = txinfo.tx.txIn.zipWithIndex.find(_._1.outPoint == txinfo.input.outPoint).get._2
875- sign(txinfo.tx, txinfo.input.redeemScript , txinfo.input.txOut.amount, key, sighashType, inputIndex)
888+ sign(txinfo.tx, txinfo.input.redeemScriptOrEmptyScript , txinfo.input.txOut.amount, key, sighashType, inputIndex)
876889 }
877890
878891 def addSigs (commitTx : CommitTx , localFundingPubkey : PublicKey , remoteFundingPubkey : PublicKey , localSig : ByteVector64 , remoteSig : ByteVector64 ): CommitTx = {
@@ -881,32 +894,32 @@ object Transactions {
881894 }
882895
883896 def addSigs (mainPenaltyTx : MainPenaltyTx , revocationSig : ByteVector64 ): MainPenaltyTx = {
884- val witness = Scripts .witnessToLocalDelayedWithRevocationSig(revocationSig, mainPenaltyTx.input.redeemScript )
897+ val witness = Scripts .witnessToLocalDelayedWithRevocationSig(revocationSig, mainPenaltyTx.input.redeemScriptOrEmptyScript )
885898 mainPenaltyTx.copy(tx = mainPenaltyTx.tx.updateWitness(0 , witness))
886899 }
887900
888901 def addSigs (htlcPenaltyTx : HtlcPenaltyTx , revocationSig : ByteVector64 , revocationPubkey : PublicKey ): HtlcPenaltyTx = {
889- val witness = Scripts .witnessHtlcWithRevocationSig(revocationSig, revocationPubkey, htlcPenaltyTx.input.redeemScript )
902+ val witness = Scripts .witnessHtlcWithRevocationSig(revocationSig, revocationPubkey, htlcPenaltyTx.input.redeemScriptOrEmptyScript )
890903 htlcPenaltyTx.copy(tx = htlcPenaltyTx.tx.updateWitness(0 , witness))
891904 }
892905
893906 def addSigs (htlcSuccessTx : HtlcSuccessTx , localSig : ByteVector64 , remoteSig : ByteVector64 , paymentPreimage : ByteVector32 , commitmentFormat : CommitmentFormat ): HtlcSuccessTx = {
894- val witness = witnessHtlcSuccess(localSig, remoteSig, paymentPreimage, htlcSuccessTx.input.redeemScript , commitmentFormat)
907+ val witness = witnessHtlcSuccess(localSig, remoteSig, paymentPreimage, htlcSuccessTx.input.redeemScriptOrEmptyScript , commitmentFormat)
895908 htlcSuccessTx.copy(tx = htlcSuccessTx.tx.updateWitness(0 , witness))
896909 }
897910
898911 def addSigs (htlcTimeoutTx : HtlcTimeoutTx , localSig : ByteVector64 , remoteSig : ByteVector64 , commitmentFormat : CommitmentFormat ): HtlcTimeoutTx = {
899- val witness = witnessHtlcTimeout(localSig, remoteSig, htlcTimeoutTx.input.redeemScript , commitmentFormat)
912+ val witness = witnessHtlcTimeout(localSig, remoteSig, htlcTimeoutTx.input.redeemScriptOrEmptyScript , commitmentFormat)
900913 htlcTimeoutTx.copy(tx = htlcTimeoutTx.tx.updateWitness(0 , witness))
901914 }
902915
903916 def addSigs (claimHtlcSuccessTx : ClaimHtlcSuccessTx , localSig : ByteVector64 , paymentPreimage : ByteVector32 ): ClaimHtlcSuccessTx = {
904- val witness = witnessClaimHtlcSuccessFromCommitTx(localSig, paymentPreimage, claimHtlcSuccessTx.input.redeemScript )
917+ val witness = witnessClaimHtlcSuccessFromCommitTx(localSig, paymentPreimage, claimHtlcSuccessTx.input.redeemScriptOrEmptyScript )
905918 claimHtlcSuccessTx.copy(tx = claimHtlcSuccessTx.tx.updateWitness(0 , witness))
906919 }
907920
908921 def addSigs (claimHtlcTimeoutTx : ClaimHtlcTimeoutTx , localSig : ByteVector64 ): ClaimHtlcTimeoutTx = {
909- val witness = witnessClaimHtlcTimeoutFromCommitTx(localSig, claimHtlcTimeoutTx.input.redeemScript )
922+ val witness = witnessClaimHtlcTimeoutFromCommitTx(localSig, claimHtlcTimeoutTx.input.redeemScriptOrEmptyScript )
910923 claimHtlcTimeoutTx.copy(tx = claimHtlcTimeoutTx.tx.updateWitness(0 , witness))
911924 }
912925
@@ -916,27 +929,27 @@ object Transactions {
916929 }
917930
918931 def addSigs (claimRemoteDelayedOutputTx : ClaimRemoteDelayedOutputTx , localSig : ByteVector64 ): ClaimRemoteDelayedOutputTx = {
919- val witness = witnessClaimToRemoteDelayedFromCommitTx(localSig, claimRemoteDelayedOutputTx.input.redeemScript )
932+ val witness = witnessClaimToRemoteDelayedFromCommitTx(localSig, claimRemoteDelayedOutputTx.input.redeemScriptOrEmptyScript )
920933 claimRemoteDelayedOutputTx.copy(tx = claimRemoteDelayedOutputTx.tx.updateWitness(0 , witness))
921934 }
922935
923936 def addSigs (claimDelayedOutputTx : ClaimLocalDelayedOutputTx , localSig : ByteVector64 ): ClaimLocalDelayedOutputTx = {
924- val witness = witnessToLocalDelayedAfterDelay(localSig, claimDelayedOutputTx.input.redeemScript )
937+ val witness = witnessToLocalDelayedAfterDelay(localSig, claimDelayedOutputTx.input.redeemScriptOrEmptyScript )
925938 claimDelayedOutputTx.copy(tx = claimDelayedOutputTx.tx.updateWitness(0 , witness))
926939 }
927940
928941 def addSigs (htlcDelayedTx : HtlcDelayedTx , localSig : ByteVector64 ): HtlcDelayedTx = {
929- val witness = witnessToLocalDelayedAfterDelay(localSig, htlcDelayedTx.input.redeemScript )
942+ val witness = witnessToLocalDelayedAfterDelay(localSig, htlcDelayedTx.input.redeemScriptOrEmptyScript )
930943 htlcDelayedTx.copy(tx = htlcDelayedTx.tx.updateWitness(0 , witness))
931944 }
932945
933946 def addSigs (claimAnchorOutputTx : ClaimLocalAnchorOutputTx , localSig : ByteVector64 ): ClaimLocalAnchorOutputTx = {
934- val witness = witnessAnchor(localSig, claimAnchorOutputTx.input.redeemScript )
947+ val witness = witnessAnchor(localSig, claimAnchorOutputTx.input.redeemScriptOrEmptyScript )
935948 claimAnchorOutputTx.copy(tx = claimAnchorOutputTx.tx.updateWitness(0 , witness))
936949 }
937950
938951 def addSigs (claimHtlcDelayedPenalty : ClaimHtlcDelayedOutputPenaltyTx , revocationSig : ByteVector64 ): ClaimHtlcDelayedOutputPenaltyTx = {
939- val witness = Scripts .witnessToLocalDelayedWithRevocationSig(revocationSig, claimHtlcDelayedPenalty.input.redeemScript )
952+ val witness = Scripts .witnessToLocalDelayedWithRevocationSig(revocationSig, claimHtlcDelayedPenalty.input.redeemScriptOrEmptyScript )
940953 claimHtlcDelayedPenalty.copy(tx = claimHtlcDelayedPenalty.tx.updateWitness(0 , witness))
941954 }
942955
0 commit comments