|
1 | 1 | package fr.acinq.eclair.wire.internal.channel.version4 |
2 | 2 |
|
3 | 3 | import com.softwaremill.quicklens.ModifyPimp |
4 | | -import fr.acinq.bitcoin.scalacompat.{DeterministicWallet, OutPoint, Satoshi, SatoshiLong, Script, Transaction, TxIn, TxOut} |
| 4 | +import fr.acinq.bitcoin.scalacompat.Crypto.PrivateKey |
| 5 | +import fr.acinq.bitcoin.scalacompat.{ByteVector32, DeterministicWallet, OutPoint, Satoshi, SatoshiLong, Script, Transaction, TxId, TxIn, TxOut} |
5 | 6 | import fr.acinq.eclair.FeatureSupport.{Mandatory, Optional} |
6 | 7 | import fr.acinq.eclair.Features.{ChannelRangeQueries, PaymentSecret, VariableLengthOnion} |
7 | 8 | import fr.acinq.eclair.TestUtils.randomTxId |
8 | | -import fr.acinq.eclair.blockchain.fee.FeeratePerKw |
| 9 | +import fr.acinq.eclair.blockchain.fee.{FeeratePerByte, FeeratePerKw} |
| 10 | +import fr.acinq.eclair.channel.LocalFundingStatus.DualFundedUnconfirmedFundingTx |
9 | 11 | import fr.acinq.eclair.channel._ |
10 | 12 | import fr.acinq.eclair.channel.fund.InteractiveTxBuilder.{InteractiveTxParams, PartiallySignedSharedTransaction, RequireConfirmedInputs, SharedTransaction} |
11 | 13 | import fr.acinq.eclair.channel.fund.InteractiveTxSigningSession.UnsignedLocalCommit |
12 | 14 | import fr.acinq.eclair.channel.fund.{InteractiveTxBuilder, InteractiveTxSigningSession} |
13 | | -import fr.acinq.eclair.transactions.CommitmentSpec |
14 | 15 | import fr.acinq.eclair.transactions.Transactions.{CommitTx, InputInfo} |
| 16 | +import fr.acinq.eclair.transactions.{CommitmentSpec, Scripts} |
15 | 17 | import fr.acinq.eclair.wire.internal.channel.ChannelCodecsSpec.normal |
16 | | -import fr.acinq.eclair.wire.internal.channel.version4.ChannelCodecs4.Codecs.{channelConfigCodec, localParamsCodec, rbfStatusCodec, remoteParamsCodec} |
| 18 | +import fr.acinq.eclair.wire.internal.channel.version4.ChannelCodecs4.Codecs._ |
17 | 19 | import fr.acinq.eclair.wire.internal.channel.version4.ChannelCodecs4.channelDataCodec |
18 | 20 | import fr.acinq.eclair.wire.protocol.TxSignatures |
19 | | -import fr.acinq.eclair.{CltvExpiryDelta, Features, MilliSatoshi, MilliSatoshiLong, UInt64, randomBytes32, randomKey} |
| 21 | +import fr.acinq.eclair.{BlockHeight, CltvExpiryDelta, Features, MilliSatoshi, MilliSatoshiLong, UInt64, randomBytes32, randomKey} |
20 | 22 | import org.scalatest.funsuite.AnyFunSuite |
21 | 23 | import scodec.bits._ |
22 | 24 |
|
@@ -154,4 +156,34 @@ class ChannelCodecs4Spec extends AnyFunSuite { |
154 | 156 | } |
155 | 157 | } |
156 | 158 |
|
| 159 | + test("decode unconfirmed dual funded") { |
| 160 | + // data encoded with the previous version of eclair, when Shared.Input did not include a pubkey script |
| 161 | + val raw = ByteVector.fromValidHex("0x020001ff02000000000000002a2400000000000000000000000000000000000000000000000000000000000000000000000000003039000000000000006400000000000000c8000000000000012c02000000000000002b04deadbeef000000000000006400000000000000c8000000000000012c00000000000000000000000042000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000000000ff000000000000006400000000000000c8ff0001240000000000000000000000000000000000000000000000000000000000000000000000002be803000000000000220020eb72e573a9513d982a01f0e6a6b53e92764db81a0c26d2be94c5fc5b69a0db7d475221024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d076621031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f52ae00000000024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f000000000000000000000000014a000002ee0000") |
| 162 | + val decoded = fundingTxStatusCodec.decode(raw.bits).require.value.asInstanceOf[LocalFundingStatus.DualFundedUnconfirmedFundingTx] |
| 163 | + |
| 164 | + // check that our codec will set the pubkeyscript using the one from the funding params |
| 165 | + val channelId = ByteVector32.Zeroes |
| 166 | + val script = Scripts.multiSig2of2(PrivateKey(ByteVector.fromValidHex("01" * 32)).publicKey, PrivateKey(ByteVector.fromValidHex("02" * 32)).publicKey) |
| 167 | + val dualFundedUnconfirmedFundingTx = DualFundedUnconfirmedFundingTx( |
| 168 | + PartiallySignedSharedTransaction( |
| 169 | + SharedTransaction( |
| 170 | + // we include the correct pubkey script here |
| 171 | + Some(InteractiveTxBuilder.Input.Shared(UInt64(42), OutPoint(TxId(ByteVector32.Zeroes), 0), Script.write(Script.pay2wsh(script)), 12345L, MilliSatoshi(100), MilliSatoshi(200), MilliSatoshi(300))), |
| 172 | + sharedOutput = InteractiveTxBuilder.Output.Shared(UInt64(43), ByteVector.fromValidHex("deadbeef"), MilliSatoshi(100), MilliSatoshi(200), MilliSatoshi(300)), |
| 173 | + localInputs = Nil, remoteInputs = Nil, localOutputs = Nil, remoteOutputs = Nil, lockTime = 0 |
| 174 | + ), |
| 175 | + localSigs = TxSignatures(channelId, TxId(ByteVector32.Zeroes), Nil) |
| 176 | + ), |
| 177 | + createdAt = BlockHeight(1000), |
| 178 | + fundingParams = InteractiveTxParams(channelId = channelId, isInitiator = true, localContribution = 100.sat, remoteContribution = 200.sat, |
| 179 | + sharedInput_opt = Some(InteractiveTxBuilder.Multisig2of2Input( |
| 180 | + InputInfo(OutPoint(TxId(ByteVector32.Zeroes), 0), TxOut(1000.sat, Script.pay2wsh(script)), script), |
| 181 | + 0, |
| 182 | + PrivateKey(ByteVector.fromValidHex("02" * 32)).publicKey |
| 183 | + )), |
| 184 | + remoteFundingPubKey = PrivateKey(ByteVector.fromValidHex("01" * 32)).publicKey, |
| 185 | + localOutputs = Nil, lockTime = 0, dustLimit = 330.sat, targetFeerate = FeeratePerKw(FeeratePerByte(3.sat)), requireConfirmedInputs = RequireConfirmedInputs(false, false)) |
| 186 | + ) |
| 187 | + assert(decoded == dualFundedUnconfirmedFundingTx) |
| 188 | + } |
157 | 189 | } |
0 commit comments