From c85f6bb364bd32ea965c082aba0957a524b48e86 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Fri, 13 Mar 2020 16:57:48 -0700 Subject: [PATCH] lnwallet: mark channel as frozen based on ShimIntent In this commit, we make the internal channel funding flow aware of frozen channels. We also update the testSingleFunderReservationWorkflow method to ensure that the created channels have the proper type bit set. --- lnwallet/interface_test.go | 39 ++++++++++++++++++++++++++++---------- lnwallet/reservation.go | 11 +++++++++-- lnwallet/wallet.go | 34 ++++++++++++++++++++------------- 3 files changed, 59 insertions(+), 25 deletions(-) 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, )