@@ -4,7 +4,7 @@ import fr.acinq.bitcoin.ScriptTree
44import fr .acinq .bitcoin .crypto .musig2 .IndividualNonce
55import fr .acinq .bitcoin .scalacompat .Crypto .PublicKey
66import fr .acinq .bitcoin .scalacompat .DeterministicWallet .KeyPath
7- import fr .acinq .bitcoin .scalacompat .{Crypto , OutPoint , ScriptWitness , Transaction , TxOut }
7+ import fr .acinq .bitcoin .scalacompat .{ByteVector64 , OutPoint , ScriptWitness , Transaction , TxOut }
88import fr .acinq .eclair .blockchain .fee .{ConfirmationPriority , ConfirmationTarget }
99import fr .acinq .eclair .channel .LocalFundingStatus ._
1010import fr .acinq .eclair .channel ._
@@ -111,12 +111,27 @@ private[channel] object ChannelCodecs4 {
111111
112112 val txCodec : Codec [Transaction ] = lengthDelimited(bytes.xmap(d => Transaction .read(d.toArray), d => Transaction .write(d)))
113113
114- val dummyScriptTreeCodec : Codec [ScriptTreeAndInternalKey ] = provide( ScriptTreeAndInternalKey ( new ScriptTree .Leaf ( 0 , java.util. List .of( ), 0 ), Crypto . PrivateKey ( ByteVector .fromValidHex( " 01 " * 32 )).xOnlyPublicKey( )))
114+ val scriptTreeCodec : Codec [ScriptTree ] = lengthDelimited(bytes.xmap(d => ScriptTree .read(d.toArray ), d => ByteVector .view(d.write() )))
115115
116- val inputInfoCodec : Codec [InputInfo ] = (
116+ val scriptTreeAndInternalKey : Codec [ScriptTreeAndInternalKey ] = (scriptTreeCodec :: xonlyPublicKey).as[ScriptTreeAndInternalKey ]
117+
118+
119+ private case class InputInfoEx (outPoint : OutPoint , txOut : TxOut , redeemScript : ByteVector , redeemScriptOrScriptTree : Either [ByteVector , ScriptTreeAndInternalKey ], dummy : Boolean )
120+
121+ // To support the change from redeemScript to "either redeem script or script tree" while remaining backwards-compatible with the previous version 4 codec, we use
122+ // the redeem script itself as a left/write indicator: empty -> right, not empty -> left
123+ private val inputInfoExCodec : Codec [InputInfoEx ] = (
117124 (" outPoint" | outPointCodec) ::
118125 (" txOut" | txOutCodec) ::
119- (" redeemScript" | either[ByteVector , ScriptTreeAndInternalKey ](provide(false ), lengthDelimited(bytes), dummyScriptTreeCodec))).as[InputInfo ]
126+ ((" redeemScript" | lengthDelimited(bytes)) >>:~ { redeemScript =>
127+ (" redeemScriptOrScriptTree" | either(provide(redeemScript.isEmpty), provide(redeemScript), scriptTreeAndInternalKey)) :: (" dummy" | provide(false ))
128+ })
129+ ).as[InputInfoEx ]
130+
131+ val inputInfoCodec : Codec [InputInfo ] = inputInfoExCodec.xmap(
132+ iex => InputInfo (iex.outPoint, iex.txOut, iex.redeemScriptOrScriptTree),
133+ i => InputInfoEx (i.outPoint, i.txOut, i.redeemScriptOrScriptTree.swap.toOption.getOrElse(ByteVector .empty), i.redeemScriptOrScriptTree, false )
134+ )
120135
121136 val outputInfoCodec : Codec [OutputInfo ] = (
122137 (" index" | uint32) ::
@@ -187,9 +202,19 @@ private[channel] object ChannelCodecs4 {
187202 (" txinfo" | htlcTxCodec) ::
188203 (" remoteSig" | bytes64)).as[HtlcTxAndRemoteSig ]
189204
190- val commitTxAndRemoteSigCodec : Codec [CommitTxAndRemoteSig ] = (
205+ private case class CommitTxAndRemoteSigEx (commitTx : CommitTx , remoteSig : ByteVector64 , partialSig : Either [ByteVector64 , PartialSignatureWithNonce ], dummy : Boolean )
206+
207+ // remoteSig is now either a signature or a partial signature with nonce. To retain compatibility with the previous codec, we use remoteSig as a left/write indicator,
208+ // a value of all zeroes meaning right (a valid signature cannot be all zeroes)
209+ private val commitTxAndRemoteSigExCodec : Codec [CommitTxAndRemoteSigEx ] = (
191210 (" commitTx" | commitTxCodec) ::
192- (" remoteSig" | either(provide(false ), bytes64, partialSignatureWithNonce))).as[CommitTxAndRemoteSig ]
211+ ((" remoteSig" | bytes64) >>:~ { remoteSig => either(provide(remoteSig == ByteVector64 .Zeroes ), provide(remoteSig), partialSignatureWithNonce) :: (" dummy" | provide(false )) })
212+ ).as[CommitTxAndRemoteSigEx ]
213+
214+ val commitTxAndRemoteSigCodec : Codec [CommitTxAndRemoteSig ] = commitTxAndRemoteSigExCodec.xmap(
215+ ce => CommitTxAndRemoteSig (ce.commitTx, ce.partialSig),
216+ c => CommitTxAndRemoteSigEx (c.commitTx, c.remoteSig.swap.toOption.getOrElse(fr.acinq.bitcoin.scalacompat.ByteVector64 .Zeroes ), c.remoteSig, false )
217+ )
193218
194219 val updateMessageCodec : Codec [UpdateMessage ] = lengthDelimited(lightningMessageCodec.narrow[UpdateMessage ](f => Attempt .successful(f.asInstanceOf [UpdateMessage ]), g => g))
195220
@@ -252,8 +277,15 @@ private[channel] object ChannelCodecs4 {
252277 (" fundingTxIndex" | uint32) ::
253278 (" remoteFundingPubkey" | publicKey)).as[InteractiveTxBuilder .Multisig2of2Input ]
254279
280+ private val musig2of2InputCodec : Codec [InteractiveTxBuilder .Musig2Input ] = (
281+ (" info" | inputInfoCodec) ::
282+ (" fundingTxIndex" | uint32) ::
283+ (" remoteFundingPubkey" | publicKey) ::
284+ (" commitIndex" | uint32)).as[InteractiveTxBuilder .Musig2Input ]
285+
255286 private val sharedFundingInputCodec : Codec [InteractiveTxBuilder .SharedFundingInput ] = discriminated[InteractiveTxBuilder .SharedFundingInput ].by(uint16)
256287 .typecase(0x01 , multisig2of2InputCodec)
288+ .typecase(0x02 , musig2of2InputCodec)
257289
258290 private val requireConfirmedInputsCodec : Codec [InteractiveTxBuilder .RequireConfirmedInputs ] = ((" forLocal" | bool8) :: (" forRemote" | bool8)).as[InteractiveTxBuilder .RequireConfirmedInputs ]
259291
@@ -638,6 +670,15 @@ private[channel] object ChannelCodecs4 {
638670 val DATA_WAIT_FOR_CHANNEL_READY_0b_Codec : Codec [DATA_WAIT_FOR_CHANNEL_READY ] = (
639671 (" commitments" | versionedCommitmentsCodec) ::
640672 (" shortIds" | shortids)).as[DATA_WAIT_FOR_CHANNEL_READY ]
673+
674+ val DATA_WAIT_FOR_DUAL_FUNDING_SIGNED_13_Codec : Codec [DATA_WAIT_FOR_DUAL_FUNDING_SIGNED ] = (
675+ (" channelParams" | paramsCodec) ::
676+ (" secondRemotePerCommitmentPoint" | publicKey) ::
677+ (" localPushAmount" | millisatoshi) ::
678+ (" remotePushAmount" | millisatoshi) ::
679+ (" status" | interactiveTxWaitingForSigsCodec) ::
680+ (" remoteChannelData_opt" | optional(bool8, varsizebinarydata)) ::
681+ (" secondRemoteNonce_opt" | optional(bool8, publicNonce))).as[DATA_WAIT_FOR_DUAL_FUNDING_SIGNED ]
641682
642683 val DATA_WAIT_FOR_DUAL_FUNDING_SIGNED_09_Codec : Codec [DATA_WAIT_FOR_DUAL_FUNDING_SIGNED ] = (
643684 (" channelParams" | paramsCodec) ::
@@ -755,6 +796,7 @@ private[channel] object ChannelCodecs4 {
755796
756797 // Order matters!
757798 val channelDataCodec : Codec [PersistentChannelData ] = discriminated[PersistentChannelData ].by(uint16)
799+ .typecase(0x13 , Codecs .DATA_WAIT_FOR_DUAL_FUNDING_SIGNED_13_Codec )
758800 .typecase(0x12 , Codecs .DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT_12_Codec )
759801 .typecase(0x11 , Codecs .DATA_CLOSING_11_Codec )
760802 .typecase(0x10 , Codecs .DATA_NEGOTIATING_10_Codec )
0 commit comments