From 21c83b0744d649aefc63d8609d20f8e173283998 Mon Sep 17 00:00:00 2001 From: eugene Date: Mon, 4 Apr 2022 16:15:02 -0400 Subject: [PATCH] lnwallet: extend Reservation with alias chan-type, feature-bit flags This extends the Reservation arguments to include whether a pending channel open has negotiated the zero-conf channel type, the scid-alias channel type, and/or the scid-alias feature bit. The result of those negotiates are stored in the OpenChannel's ChanType. The arguments to NewChannelReservation have also been simplified. --- lnwallet/reservation.go | 76 ++++++++++++++++++++++----------- lnwallet/test/test_interface.go | 12 ++++-- lnwallet/wallet.go | 18 ++++++-- 3 files changed, 74 insertions(+), 32 deletions(-) diff --git a/lnwallet/reservation.go b/lnwallet/reservation.go index c36ba170e..ba9fc76c6 100644 --- a/lnwallet/reservation.go +++ b/lnwallet/reservation.go @@ -12,7 +12,6 @@ import ( "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/keychain" - "github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwallet/chanfunding" "github.com/lightningnetwork/lnd/lnwire" ) @@ -208,11 +207,9 @@ type ChannelReservation struct { // creation of all channel reservations should be carried out via the // lnwallet.InitChannelReservation interface. func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, - commitFeePerKw chainfee.SatPerKWeight, wallet *LightningWallet, - id uint64, pushMSat lnwire.MilliSatoshi, chainHash *chainhash.Hash, - flags lnwire.FundingFlag, commitType CommitmentType, - fundingAssembler chanfunding.Assembler, - pendingChanID [32]byte, thawHeight uint32) (*ChannelReservation, error) { + wallet *LightningWallet, id uint64, chainHash *chainhash.Hash, + thawHeight uint32, req *InitFundingReserveMsg) (*ChannelReservation, + error) { var ( ourBalance lnwire.MilliSatoshi @@ -223,10 +220,10 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, // Based on the channel type, we determine the initial commit weight // and fee. commitWeight := int64(input.CommitWeight) - if commitType.HasAnchors() { + if req.CommitType.HasAnchors() { commitWeight = int64(input.AnchorCommitWeight) } - commitFee := commitFeePerKw.FeeForWeight(commitWeight) + commitFee := req.CommitFeePerKw.FeeForWeight(commitWeight) localFundingMSat := lnwire.NewMSatFromSatoshis(localFundingAmt) // TODO(halseth): make method take remote funding amount directly @@ -236,7 +233,7 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, // The total fee paid by the initiator will be the commitment fee in // addition to the two anchor outputs. feeMSat := lnwire.NewMSatFromSatoshis(commitFee) - if commitType.HasAnchors() { + if req.CommitType.HasAnchors() { feeMSat += 2 * lnwire.NewMSatFromSatoshis(anchorSize) } @@ -247,8 +244,8 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, // no initial balance in the channel unless the remote party is pushing // some funds to us within the first commitment state. if localFundingAmt == 0 { - ourBalance = pushMSat - theirBalance = capacityMSat - feeMSat - pushMSat + ourBalance = req.PushMSat + theirBalance = capacityMSat - feeMSat - req.PushMSat initiator = false // If the responder doesn't have enough funds to actually pay @@ -268,14 +265,14 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, // we pay all the initial fees within the commitment // transaction. We also deduct our balance by the // amount pushed as part of the initial state. - ourBalance = capacityMSat - feeMSat - pushMSat - theirBalance = pushMSat + ourBalance = capacityMSat - feeMSat - req.PushMSat + theirBalance = req.PushMSat } else { // Otherwise, this is a dual funder workflow where both // slides split the amount funded and the commitment // fee. ourBalance = localFundingMSat - (feeMSat / 2) - theirBalance = capacityMSat - localFundingMSat - (feeMSat / 2) + pushMSat + theirBalance = capacityMSat - localFundingMSat - (feeMSat / 2) + req.PushMSat } initiator = true @@ -320,16 +317,16 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, // If either of the balances are zero at this point, or we have a // 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 ourBalance == 0 || theirBalance == 0 || req.PushMSat != 0 { // Both the tweakless type and the anchor type is tweakless, // hence set the bit. - if commitType.HasStaticRemoteKey() { + if req.CommitType.HasStaticRemoteKey() { chanType |= channeldb.SingleFunderTweaklessBit } else { chanType |= channeldb.SingleFunderBit } - switch a := fundingAssembler.(type) { + switch a := req.ChanFunder.(type) { // The first channels of a batch shouldn't publish the batch TX // to avoid problems if some of the funding flows can't be // completed. Only the last channel of a batch should publish. @@ -358,14 +355,14 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, // We are adding anchor outputs to our commitment. We only support this // in combination with zero-fee second-levels HTLCs. - if commitType.HasAnchors() { + if req.CommitType.HasAnchors() { chanType |= channeldb.AnchorOutputsBit chanType |= channeldb.ZeroHtlcTxFeeBit } // Set the appropriate LeaseExpiration/Frozen bit based on the // reservation parameters. - if commitType == CommitmentTypeScriptEnforcedLease { + if req.CommitType == CommitmentTypeScriptEnforcedLease { if thawHeight == 0 { return nil, errors.New("missing absolute expiration " + "for script enforced lease commitment type") @@ -375,6 +372,18 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, chanType |= channeldb.FrozenBit } + if req.ZeroConf { + chanType |= channeldb.ZeroConfBit + } + + if req.OptionScidAlias { + chanType |= channeldb.ScidAliasChanBit + } + + if req.ScidAliasFeature { + chanType |= channeldb.ScidAliasFeatureBit + } + return &ChannelReservation{ ourContribution: &ChannelContribution{ FundingAmount: ourBalance.ToSatoshis(), @@ -389,18 +398,18 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, ChainHash: *chainHash, IsPending: true, IsInitiator: initiator, - ChannelFlags: flags, + ChannelFlags: req.Flags, Capacity: capacity, LocalCommitment: channeldb.ChannelCommitment{ LocalBalance: ourBalance, RemoteBalance: theirBalance, - FeePerKw: btcutil.Amount(commitFeePerKw), + FeePerKw: btcutil.Amount(req.CommitFeePerKw), CommitFee: commitFee, }, RemoteCommitment: channeldb.ChannelCommitment{ LocalBalance: ourBalance, RemoteBalance: theirBalance, - FeePerKw: btcutil.Amount(commitFeePerKw), + FeePerKw: btcutil.Amount(req.CommitFeePerKw), CommitFee: commitFee, }, ThawHeight: thawHeight, @@ -408,14 +417,22 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, InitialLocalBalance: ourBalance, InitialRemoteBalance: theirBalance, }, - pushMSat: pushMSat, - pendingChanID: pendingChanID, + pushMSat: req.PushMSat, + pendingChanID: req.PendingChanID, reservationID: id, wallet: wallet, - chanFunder: fundingAssembler, + chanFunder: req.ChanFunder, }, nil } +// AddAlias stores the first alias for zero-conf channels. +func (r *ChannelReservation) AddAlias(scid lnwire.ShortChannelID) { + r.Lock() + defer r.Unlock() + + r.partialState.ShortChannelID = scid +} + // SetNumConfsRequired sets the number of confirmations that are required for // the ultimate funding transaction before the channel can be considered open. // This is distinct from the main reservation workflow as it allows @@ -428,6 +445,15 @@ func (r *ChannelReservation) SetNumConfsRequired(numConfs uint16) { r.partialState.NumConfsRequired = numConfs } +// IsZeroConf returns if the reservation's underlying partial channel state is +// a zero-conf channel. +func (r *ChannelReservation) IsZeroConf() bool { + r.RLock() + defer r.RUnlock() + + return r.partialState.IsZeroConf() +} + // CommitConstraints takes the constraints that the remote party specifies for // the type of commitments that we can generate for them. These constraints // include several parameters that serve as flow control restricting the amount diff --git a/lnwallet/test/test_interface.go b/lnwallet/test/test_interface.go index 6225227cf..dd741fd4c 100644 --- a/lnwallet/test/test_interface.go +++ b/lnwallet/test/test_interface.go @@ -728,11 +728,17 @@ func testCancelNonExistentReservation(miner *rpctest.Harness, feePerKw, err := alice.Cfg.FeeEstimator.EstimateFeePerKW(1) require.NoError(t, err, "unable to query fee estimator") + req := &lnwallet.InitFundingReserveMsg{ + CommitFeePerKw: feePerKw, + PushMSat: 10, + Flags: lnwire.FFAnnounceChannel, + CommitType: lnwallet.CommitmentTypeTweakless, + PendingChanID: [32]byte{}, + } + // Create our own reservation, give it some ID. res, err := lnwallet.NewChannelReservation( - 10000, 10000, feePerKw, alice, 22, 10, &testHdSeed, - lnwire.FFAnnounceChannel, lnwallet.CommitmentTypeTweakless, - nil, [32]byte{}, 0, + 10000, 10000, alice, 22, &testHdSeed, 0, req, ) require.NoError(t, err, "unable to create res") diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index 9e0bac3e6..f3868695f 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -153,6 +153,18 @@ type InitFundingReserveMsg struct { // used. ChanFunder chanfunding.Assembler + // ZeroConf is a boolean that is true if a zero-conf channel was + // negotiated. + ZeroConf bool + + // OptionScidAlias is a boolean that is true if an option-scid-alias + // channel type was explicitly negotiated. + OptionScidAlias bool + + // ScidAliasFeature is true if the option-scid-alias feature bit was + // negotiated. + ScidAliasFeature bool + // err is a channel in which all errors will be sent across. Will be // nil if this initial set is successful. // @@ -845,10 +857,8 @@ func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg id := atomic.AddUint64(&l.nextFundingID, 1) reservation, err := NewChannelReservation( - capacity, localFundingAmt, req.CommitFeePerKw, l, id, - req.PushMSat, l.Cfg.NetParams.GenesisHash, req.Flags, - req.CommitType, req.ChanFunder, req.PendingChanID, - thawHeight, + capacity, localFundingAmt, l, id, l.Cfg.NetParams.GenesisHash, + thawHeight, req, ) if err != nil { fundingIntent.Cancel()