diff --git a/fundingmanager.go b/fundingmanager.go index 7913a11f..bf4ed31b 100644 --- a/fundingmanager.go +++ b/fundingmanager.go @@ -1106,6 +1106,28 @@ func (f *fundingManager) processFundingOpen(msg *lnwire.OpenChannel, } } +// commitmentType returns the commitment type to use for the channel, based on +// the features the two peers have available. +func commitmentType(localFeatures, + remoteFeatures *lnwire.FeatureVector) lnwallet.CommitmentType { + + localTweakless := localFeatures.HasFeature( + lnwire.StaticRemoteKeyOptional, + ) + remoteTweakless := remoteFeatures.HasFeature( + lnwire.StaticRemoteKeyOptional, + ) + + // If both nodes are signaling the proper feature bit for tweakless + // copmmitments, we'll use that. + if localTweakless && remoteTweakless { + return lnwallet.CommitmentTypeTweakless + } + + // Otherwise we'll fall back to the legacy type. + return lnwallet.CommitmentTypeLegacy +} + // handleFundingOpen creates an initial 'ChannelReservation' within the wallet, // then responds to the source peer with an accept channel message progressing // the funding workflow. @@ -1228,13 +1250,9 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) { // negotiated the new tweakless commitment format. This is only the // case if *both* us and the remote peer are signaling the proper // feature bit. - localTweakless := fmsg.peer.LocalFeatures().HasFeature( - lnwire.StaticRemoteKeyOptional, + commitType := commitmentType( + fmsg.peer.LocalFeatures(), fmsg.peer.RemoteFeatures(), ) - remoteTweakless := fmsg.peer.RemoteFeatures().HasFeature( - lnwire.StaticRemoteKeyOptional, - ) - tweaklessCommitment := localTweakless && remoteTweakless chainHash := chainhash.Hash(msg.ChainHash) req := &lnwallet.InitFundingReserveMsg{ ChainHash: &chainHash, @@ -1248,7 +1266,7 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) { PushMSat: msg.PushAmount, Flags: msg.ChannelFlags, MinConfs: 1, - Tweakless: tweaklessCommitment, + CommitType: commitType, } reservation, err := f.cfg.Wallet.InitChannelReservation(req) @@ -1307,9 +1325,9 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) { reservation.SetOurUpfrontShutdown(shutdown) fndgLog.Infof("Requiring %v confirmations for pendingChan(%x): "+ - "amt=%v, push_amt=%v, tweakless=%v, upfrontShutdown=%x", numConfsReq, + "amt=%v, push_amt=%v, committype=%v, upfrontShutdown=%x", numConfsReq, fmsg.msg.PendingChannelID, amt, msg.PushAmount, - tweaklessCommitment, msg.UpfrontShutdownScript) + commitType, msg.UpfrontShutdownScript) // Generate our required constraints for the remote party. remoteCsvDelay := f.cfg.RequiredRemoteDelay(amt) @@ -2904,13 +2922,9 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) { // negotiated the new tweakless commitment format. This is only the // case if *both* us and the remote peer are signaling the proper // feature bit. - localTweakless := msg.peer.LocalFeatures().HasFeature( - lnwire.StaticRemoteKeyOptional, + commitType := commitmentType( + msg.peer.LocalFeatures(), msg.peer.RemoteFeatures(), ) - remoteTweakless := msg.peer.RemoteFeatures().HasFeature( - lnwire.StaticRemoteKeyOptional, - ) - tweaklessCommitment := localTweakless && remoteTweakless req := &lnwallet.InitFundingReserveMsg{ ChainHash: &msg.chainHash, PendingChanID: chanID, @@ -2924,7 +2938,7 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) { PushMSat: msg.pushAmt, Flags: channelFlags, MinConfs: msg.minConfs, - Tweakless: tweaklessCommitment, + CommitType: commitType, ChanFunder: msg.chanFunder, } @@ -3012,7 +3026,7 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) { maxHtlcs := f.cfg.RequiredRemoteMaxHTLCs(capacity) fndgLog.Infof("Starting funding workflow with %v for pending_id(%x), "+ - "tweakless=%v", msg.peer.Address(), chanID, tweaklessCommitment) + "committype=%v", msg.peer.Address(), chanID, commitType) fundingOpen := lnwire.OpenChannel{ ChainHash: *f.cfg.Wallet.Cfg.NetParams.GenesisHash, diff --git a/lnwallet/interface_test.go b/lnwallet/interface_test.go index db907d5a..6ebb7ff9 100644 --- a/lnwallet/interface_test.go +++ b/lnwallet/interface_test.go @@ -700,7 +700,8 @@ func testCancelNonExistentReservation(miner *rpctest.Harness, // Create our own reservation, give it some ID. res, err := lnwallet.NewChannelReservation( 10000, 10000, feePerKw, alice, 22, 10, &testHdSeed, - lnwire.FFAnnounceChannel, true, nil, [32]byte{}, + lnwire.FFAnnounceChannel, lnwallet.CommitmentTypeTweakless, + nil, [32]byte{}, ) if err != nil { t.Fatalf("unable to create res: %v", err) @@ -738,7 +739,7 @@ func testReservationInitiatorBalanceBelowDustCancel(miner *rpctest.Harness, FundingFeePerKw: 1000, PushMSat: 0, Flags: lnwire.FFAnnounceChannel, - Tweakless: true, + CommitType: lnwallet.CommitmentTypeTweakless, } _, err = alice.InitChannelReservation(req) switch { @@ -793,7 +794,8 @@ func assertContributionInitPopulated(t *testing.T, c *lnwallet.ChannelContributi } func testSingleFunderReservationWorkflow(miner *rpctest.Harness, - alice, bob *lnwallet.LightningWallet, t *testing.T, tweakless bool, + alice, bob *lnwallet.LightningWallet, t *testing.T, + commitType lnwallet.CommitmentType, aliceChanFunder chanfunding.Assembler, fetchFundingTx func() *wire.MsgTx, pendingChanID [32]byte) { @@ -823,7 +825,7 @@ func testSingleFunderReservationWorkflow(miner *rpctest.Harness, FundingFeePerKw: feePerKw, PushMSat: pushAmt, Flags: lnwire.FFAnnounceChannel, - Tweakless: tweakless, + CommitType: commitType, ChanFunder: aliceChanFunder, } aliceChanReservation, err := alice.InitChannelReservation(aliceReq) @@ -874,7 +876,7 @@ func testSingleFunderReservationWorkflow(miner *rpctest.Harness, FundingFeePerKw: feePerKw, PushMSat: pushAmt, Flags: lnwire.FFAnnounceChannel, - Tweakless: tweakless, + CommitType: commitType, } bobChanReservation, err := bob.InitChannelReservation(bobReq) if err != nil { @@ -2543,7 +2545,8 @@ var walletTests = []walletTestCase{ bob *lnwallet.LightningWallet, t *testing.T) { testSingleFunderReservationWorkflow( - miner, alice, bob, t, false, nil, nil, + miner, alice, bob, t, + lnwallet.CommitmentTypeLegacy, nil, nil, [32]byte{}, ) }, @@ -2554,7 +2557,8 @@ var walletTests = []walletTestCase{ bob *lnwallet.LightningWallet, t *testing.T) { testSingleFunderReservationWorkflow( - miner, alice, bob, t, true, nil, nil, + miner, alice, bob, t, + lnwallet.CommitmentTypeTweakless, nil, nil, [32]byte{}, ) }, @@ -2809,8 +2813,8 @@ func testSingleFunderExternalFundingTx(miner *rpctest.Harness, // pending channel ID generated above to allow Alice and Bob to track // the funding flow externally. testSingleFunderReservationWorkflow( - miner, alice, bob, t, true, aliceExternalFunder, - func() *wire.MsgTx { + miner, alice, bob, t, lnwallet.CommitmentTypeTweakless, + aliceExternalFunder, func() *wire.MsgTx { return fundingTx }, pendingChanID, ) diff --git a/lnwallet/reservation.go b/lnwallet/reservation.go index c371f6f0..ba4c631e 100644 --- a/lnwallet/reservation.go +++ b/lnwallet/reservation.go @@ -15,6 +15,32 @@ import ( "github.com/lightningnetwork/lnd/lnwire" ) +// CommitmentType is an enum indicating the commitment type we should use for +// the channel we are opening. +type CommitmentType int + +const ( + // CommitmentTypeLegacy is the legacy commitment format with a tweaked + // to_remote key. + CommitmentTypeLegacy = iota + + // CommitmentTypeTweakless is a newer commitment format where the + // to_remote key is static. + CommitmentTypeTweakless +) + +// String returns the name of the CommitmentType. +func (c CommitmentType) String() string { + switch c { + case CommitmentTypeLegacy: + return "legacy" + case CommitmentTypeTweakless: + return "tweakless" + default: + return "invalid" + } +} + // ChannelContribution is the primary constituent of the funding workflow // within lnwallet. Each side first exchanges their respective contributions // along with channel specific parameters like the min fee/KB. Once @@ -136,7 +162,7 @@ type ChannelReservation struct { func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, commitFeePerKw chainfee.SatPerKWeight, wallet *LightningWallet, id uint64, pushMSat lnwire.MilliSatoshi, chainHash *chainhash.Hash, - flags lnwire.FundingFlag, tweaklessCommit bool, + flags lnwire.FundingFlag, commitType CommitmentType, fundingAssembler chanfunding.Assembler, pendingChanID [32]byte) (*ChannelReservation, error) { @@ -231,7 +257,7 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, // non-zero push amt (there's no pushing for dual funder), then this is // a single-funder channel. if ourBalance == 0 || theirBalance == 0 || pushMSat != 0 { - if tweaklessCommit { + if commitType == CommitmentTypeTweakless { chanType |= channeldb.SingleFunderTweaklessBit } else { chanType |= channeldb.SingleFunderBit diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index 5649b652..73eaf217 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -98,9 +98,9 @@ type InitFundingReserveMsg struct { // output selected to fund the channel should satisfy. MinConfs int32 - // Tweakless indicates if the channel should use the new tweakless - // commitment format or not. - Tweakless bool + // CommitType indicates what type of commitment type the channel should + // be using, like tweakless or anchors. + CommitType CommitmentType // ChanFunder is an optional channel funder that allows the caller to // control exactly how the channel funding is carried out. If not @@ -568,7 +568,7 @@ func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg reservation, err := NewChannelReservation( capacity, localFundingAmt, req.CommitFeePerKw, l, id, req.PushMSat, l.Cfg.NetParams.GenesisHash, req.Flags, - req.Tweakless, req.ChanFunder, req.PendingChanID, + req.CommitType, req.ChanFunder, req.PendingChanID, ) if err != nil { if fundingIntent != nil {