diff --git a/lnwallet/interface_test.go b/lnwallet/interface_test.go index aae62cf3..faadaca2 100644 --- a/lnwallet/interface_test.go +++ b/lnwallet/interface_test.go @@ -701,7 +701,7 @@ func testCancelNonExistentReservation(miner *rpctest.Harness, res, err := lnwallet.NewChannelReservation( 10000, 10000, feePerKw, alice, 22, 10, &testHdSeed, lnwire.FFAnnounceChannel, lnwallet.CommitmentTypeTweakless, - nil, [32]byte{}, + nil, [32]byte{}, 0, ) if err != nil { t.Fatalf("unable to create res: %v", err) @@ -796,8 +796,8 @@ func assertContributionInitPopulated(t *testing.T, c *lnwallet.ChannelContributi func testSingleFunderReservationWorkflow(miner *rpctest.Harness, alice, bob *lnwallet.LightningWallet, t *testing.T, commitType lnwallet.CommitmentType, - aliceChanFunder chanfunding.Assembler, - fetchFundingTx func() *wire.MsgTx, pendingChanID [32]byte) { + aliceChanFunder chanfunding.Assembler, fetchFundingTx func() *wire.MsgTx, + pendingChanID [32]byte, thawHeight uint32) { // For this scenario, Alice will be the channel initiator while bob // will act as the responder to the workflow. @@ -1045,6 +1045,24 @@ func testSingleFunderReservationWorkflow(miner *rpctest.Harness, t.Fatalf("incorrect transaction was mined") } + // If a frozen channel was requested, then we expect that both channel + // types show as being a frozen channel type. + aliceChanFrozen := aliceChannels[0].ChanType.IsFrozen() + bobChanFrozen := bobChannels[0].ChanType.IsFrozen() + if thawHeight != 0 && (!aliceChanFrozen || !bobChanFrozen) { + t.Fatalf("expected both alice and bob to have frozen chans: "+ + "alice_frozen=%v, bob_frozen=%v", aliceChanFrozen, + bobChanFrozen) + } + if thawHeight != bobChannels[0].ThawHeight { + t.Fatalf("wrong thaw height: expected %v got %v", thawHeight, + bobChannels[0].ThawHeight) + } + if thawHeight != aliceChannels[0].ThawHeight { + t.Fatalf("wrong thaw height: expected %v got %v", thawHeight, + aliceChannels[0].ThawHeight) + } + assertReservationDeleted(aliceChanReservation, t) assertReservationDeleted(bobChanReservation, t) } @@ -2546,8 +2564,8 @@ var walletTests = []walletTestCase{ testSingleFunderReservationWorkflow( miner, alice, bob, t, - lnwallet.CommitmentTypeLegacy, nil, nil, - [32]byte{}, + lnwallet.CommitmentTypeLegacy, nil, + nil, [32]byte{}, 0, ) }, }, @@ -2558,8 +2576,8 @@ var walletTests = []walletTestCase{ testSingleFunderReservationWorkflow( miner, alice, bob, t, - lnwallet.CommitmentTypeTweakless, nil, nil, - [32]byte{}, + lnwallet.CommitmentTypeTweakless, nil, + nil, [32]byte{}, 0, ) }, }, @@ -2777,12 +2795,13 @@ func testSingleFunderExternalFundingTx(miner *rpctest.Harness, // Now that we have the fully constructed funding transaction, we'll // create a new shim external funder out of it for Alice, and prep a // shim intent for Bob. + thawHeight := uint32(200) aliceExternalFunder := chanfunding.NewCannedAssembler( - *chanPoint, btcutil.Amount(chanAmt), &aliceFundingKey, + thawHeight, *chanPoint, btcutil.Amount(chanAmt), &aliceFundingKey, bobFundingKey.PubKey, true, ) bobShimIntent, err := chanfunding.NewCannedAssembler( - *chanPoint, btcutil.Amount(chanAmt), &bobFundingKey, + thawHeight, *chanPoint, btcutil.Amount(chanAmt), &bobFundingKey, aliceFundingKey.PubKey, false, ).ProvisionChannel(&chanfunding.Request{ LocalAmt: btcutil.Amount(chanAmt), @@ -2816,7 +2835,7 @@ func testSingleFunderExternalFundingTx(miner *rpctest.Harness, miner, alice, bob, t, lnwallet.CommitmentTypeTweakless, aliceExternalFunder, func() *wire.MsgTx { return fundingTx - }, pendingChanID, + }, pendingChanID, thawHeight, ) } diff --git a/lnwallet/reservation.go b/lnwallet/reservation.go index 823aec4a..3c9188a6 100644 --- a/lnwallet/reservation.go +++ b/lnwallet/reservation.go @@ -171,7 +171,7 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, id uint64, pushMSat lnwire.MilliSatoshi, chainHash *chainhash.Hash, flags lnwire.FundingFlag, commitType CommitmentType, fundingAssembler chanfunding.Assembler, - pendingChanID [32]byte) (*ChannelReservation, error) { + pendingChanID [32]byte, thawHeight uint32) (*ChannelReservation, error) { var ( ourBalance lnwire.MilliSatoshi @@ -306,6 +306,12 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, chanType |= channeldb.AnchorOutputsBit } + // If the channel is meant to be frozen, then we'll set the frozen bit + // now so once the channel is open, it can be interpreted properly. + if thawHeight != 0 { + chanType |= channeldb.FrozenBit + } + return &ChannelReservation{ ourContribution: &ChannelContribution{ FundingAmount: ourBalance.ToSatoshis(), @@ -334,7 +340,8 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, FeePerKw: btcutil.Amount(commitFeePerKw), CommitFee: commitFee, }, - Db: wallet.Cfg.Database, + ThawHeight: thawHeight, + Db: wallet.Cfg.Database, }, pushMSat: pushMSat, pendingChanID: pendingChanID, diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index dbada608..06fb9bb7 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -560,6 +560,26 @@ func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg remoteFundingAmt = fundingIntent.RemoteFundingAmt() } + // If this is a shim intent, then it may be attempting to use an + // existing set of keys for the funding workflow. In this case, we'll + // make a simple wrapper keychain.KeyRing that will proxy certain + // derivation calls to future callers. + var ( + keyRing keychain.KeyRing = l.SecretKeyRing + thawHeight uint32 + ) + if shimIntent, ok := fundingIntent.(*chanfunding.ShimIntent); ok { + keyRing = &shimKeyRing{ + KeyRing: keyRing, + ShimIntent: shimIntent, + } + + // As this was a registered shim intent, we'll obtain the thaw + // height of the intent, if present at all. If this is + // non-zero, then we'll mark this as the proper channel type. + thawHeight = shimIntent.ThawHeight() + } + // The total channel capacity will be the size of the funding output we // created plus the remote contribution. capacity := localFundingAmt + remoteFundingAmt @@ -569,6 +589,7 @@ func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg capacity, localFundingAmt, req.CommitFeePerKw, l, id, req.PushMSat, l.Cfg.NetParams.GenesisHash, req.Flags, req.CommitType, req.ChanFunder, req.PendingChanID, + thawHeight, ) if err != nil { if fundingIntent != nil { @@ -580,19 +601,6 @@ func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg return } - var keyRing keychain.KeyRing = l.SecretKeyRing - - // If this is a shim intent, then it may be attempting to use an - // existing set of keys for the funding workflow. In this case, we'll - // make a simple wrapper keychain.KeyRing that will proxy certain - // derivation calls to future callers. - if shimIntent, ok := fundingIntent.(*chanfunding.ShimIntent); ok { - keyRing = &shimKeyRing{ - KeyRing: keyRing, - ShimIntent: shimIntent, - } - } - err = l.initOurContribution( reservation, fundingIntent, req.NodeAddr, req.NodeID, keyRing, )