diff --git a/lnwallet/chanfunding/assembler.go b/lnwallet/chanfunding/assembler.go index b0acd85ba..cd65da8a3 100644 --- a/lnwallet/chanfunding/assembler.go +++ b/lnwallet/chanfunding/assembler.go @@ -110,6 +110,11 @@ type Request struct { // ChangeAddr is a closure that will provide the Assembler with a // change address for the funding transaction if needed. ChangeAddr func() (btcutil.Address, error) + + // Musig2 if true, then musig2 will be used to generate the funding + // output. By definition, this'll also use segwit v1 (taproot) for the + // funding output. + Musig2 bool } // Intent is returned by an Assembler and represents the base functionality the diff --git a/lnwallet/chanfunding/canned_assembler.go b/lnwallet/chanfunding/canned_assembler.go index cf33a0cd4..cf2c55e08 100644 --- a/lnwallet/chanfunding/canned_assembler.go +++ b/lnwallet/chanfunding/canned_assembler.go @@ -35,6 +35,11 @@ type ShimIntent struct { // a normal channel. Until this height, it's considered frozen, so it // can only be cooperatively closed by the responding party. thawHeight uint32 + + // musig2 determines if the funding output should use musig2 to + // generate an aggregate key to use as the taproot-native multi-sig + // output. + musig2 bool } // FundingOutput returns the witness script, and the output that creates the @@ -48,6 +53,19 @@ func (s *ShimIntent) FundingOutput() ([]byte, *wire.TxOut, error) { } totalAmt := s.localFundingAmt + s.remoteFundingAmt + + // If musig2 is active, then we'll return a single aggregated key + // rather than using the "existing" funding script. + if s.musig2 { + // Similar to the existing p2wsh script, we'll always ensure + // the keys are sorted before use. + return input.GenTaprootFundingScript( + s.localKey.PubKey, + s.remoteKey, + int64(totalAmt), + ) + } + return input.GenFundingPkScript( s.localKey.PubKey.SerializeCompressed(), s.remoteKey.SerializeCompressed(), @@ -171,13 +189,20 @@ type CannedAssembler struct { // a normal channel. Until this height, it's considered frozen, so it // can only be cooperatively closed by the responding party. thawHeight uint32 + + // musig2 determines if the funding output should use musig2 to + // generate an aggregate key to use as the taproot-native multi-sig + // output. + musig2 bool } // NewCannedAssembler creates a new CannedAssembler from the material required // to construct a funding output and channel point. +// +// TODO(roasbeef): pass in chan type instead? func NewCannedAssembler(thawHeight uint32, chanPoint wire.OutPoint, fundingAmt btcutil.Amount, localKey *keychain.KeyDescriptor, - remoteKey *btcec.PublicKey, initiator bool) *CannedAssembler { + remoteKey *btcec.PublicKey, initiator, musig2 bool) *CannedAssembler { return &CannedAssembler{ initiator: initiator, @@ -186,6 +211,7 @@ func NewCannedAssembler(thawHeight uint32, chanPoint wire.OutPoint, fundingAmt: fundingAmt, chanPoint: chanPoint, thawHeight: thawHeight, + musig2: musig2, } } @@ -215,6 +241,7 @@ func (c *CannedAssembler) ProvisionChannel(req *Request) (Intent, error) { remoteKey: c.remoteKey, chanPoint: &c.chanPoint, thawHeight: c.thawHeight, + musig2: c.musig2, } if c.initiator { diff --git a/lnwallet/chanfunding/psbt_assembler.go b/lnwallet/chanfunding/psbt_assembler.go index f13319516..e509d5ce5 100644 --- a/lnwallet/chanfunding/psbt_assembler.go +++ b/lnwallet/chanfunding/psbt_assembler.go @@ -531,6 +531,7 @@ func (p *PsbtAssembler) ProvisionChannel(req *Request) (Intent, error) { intent := &PsbtIntent{ ShimIntent: ShimIntent{ localFundingAmt: p.fundingAmt, + musig2: req.Musig2, }, State: PsbtShimRegistered, BasePsbt: p.basePsbt, diff --git a/lnwallet/chanfunding/wallet_assembler.go b/lnwallet/chanfunding/wallet_assembler.go index 8fb2b935d..104a5c05f 100644 --- a/lnwallet/chanfunding/wallet_assembler.go +++ b/lnwallet/chanfunding/wallet_assembler.go @@ -476,6 +476,7 @@ func (w *WalletAssembler) ProvisionChannel(r *Request) (Intent, error) { ShimIntent: ShimIntent{ localFundingAmt: localContributionAmt, remoteFundingAmt: r.RemoteAmt, + musig2: r.Musig2, }, InputCoins: selectedCoins, coinLocker: w.cfg.CoinLocker, diff --git a/lnwallet/test/test_interface.go b/lnwallet/test/test_interface.go index 737f1d417..e27e12ded 100644 --- a/lnwallet/test/test_interface.go +++ b/lnwallet/test/test_interface.go @@ -2974,11 +2974,11 @@ func testSingleFunderExternalFundingTx(miner *rpctest.Harness, thawHeight := uint32(200) aliceExternalFunder := chanfunding.NewCannedAssembler( thawHeight, *chanPoint, btcutil.Amount(chanAmt), &aliceFundingKey, - bobFundingKey.PubKey, true, + bobFundingKey.PubKey, true, false, ) bobShimIntent, err := chanfunding.NewCannedAssembler( thawHeight, *chanPoint, btcutil.Amount(chanAmt), &bobFundingKey, - aliceFundingKey.PubKey, false, + aliceFundingKey.PubKey, false, false, ).ProvisionChannel(&chanfunding.Request{ LocalAmt: btcutil.Amount(chanAmt), MinConfs: 1, diff --git a/rpcserver.go b/rpcserver.go index 59b66e09e..1b1aa40eb 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -1819,10 +1819,12 @@ func newFundingShimAssembler(chanPointShim *lnrpc.ChanPointShim, initiator bool, // With all the parts assembled, we can now make the canned assembler // to pass into the wallet. + // + // TODO(roasbeef): update to support musig2 return chanfunding.NewCannedAssembler( chanPointShim.ThawHeight, *chanPoint, btcutil.Amount(chanPointShim.Amt), &localKeyDesc, - remoteKey, initiator, + remoteKey, initiator, false, ), nil }