Skip to content

Commit e2f5374

Browse files
authored
Merge pull request #7904 from lightningnetwork/simple-taproot-chans-staging
multi: merge simple taproot channels staging branch into master
2 parents e49f6fc + a87631c commit e2f5374

File tree

131 files changed

+14973
-2634
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

131 files changed

+14973
-2634
lines changed

chanbackup/single.go

+9
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ const (
4848
// commitment and HTLC outputs that pay directly to the channel
4949
// initiator.
5050
ScriptEnforcedLeaseVersion = 4
51+
52+
// SimpleTaprootVersion is a version that denotes this channel is using
53+
// the musig2 based taproot commitment format.
54+
SimpleTaprootVersion = 5
5155
)
5256

5357
// Single is a static description of an existing channel that can be used for
@@ -213,6 +217,9 @@ func NewSingle(channel *channeldb.OpenChannel,
213217
}
214218

215219
switch {
220+
case channel.ChanType.IsTaproot():
221+
single.Version = SimpleTaprootVersion
222+
216223
case channel.ChanType.HasLeaseExpiration():
217224
single.Version = ScriptEnforcedLeaseVersion
218225
single.LeaseExpiry = channel.ThawHeight
@@ -244,6 +251,7 @@ func (s *Single) Serialize(w io.Writer) error {
244251
case AnchorsCommitVersion:
245252
case AnchorsZeroFeeHtlcTxCommitVersion:
246253
case ScriptEnforcedLeaseVersion:
254+
case SimpleTaprootVersion:
247255
default:
248256
return fmt.Errorf("unable to serialize w/ unknown "+
249257
"version: %v", s.Version)
@@ -420,6 +428,7 @@ func (s *Single) Deserialize(r io.Reader) error {
420428
case AnchorsCommitVersion:
421429
case AnchorsZeroFeeHtlcTxCommitVersion:
422430
case ScriptEnforcedLeaseVersion:
431+
case SimpleTaprootVersion:
423432
default:
424433
return fmt.Errorf("unable to de-serialize w/ unknown "+
425434
"version: %v", s.Version)

channeldb/channel.go

+95-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package channeldb
22

33
import (
44
"bytes"
5+
"crypto/hmac"
56
"crypto/sha256"
67
"encoding/binary"
78
"errors"
@@ -13,6 +14,7 @@ import (
1314
"sync"
1415

1516
"github.com/btcsuite/btcd/btcec/v2"
17+
"github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
1618
"github.com/btcsuite/btcd/btcutil"
1719
"github.com/btcsuite/btcd/chaincfg/chainhash"
1820
"github.com/btcsuite/btcd/wire"
@@ -303,6 +305,10 @@ const (
303305
// ScidAliasFeatureBit indicates that the scid-alias feature bit was
304306
// negotiated during the lifetime of this channel.
305307
ScidAliasFeatureBit ChannelType = 1 << 9
308+
309+
// SimpleTaprootFeatureBit indicates that the simple-taproot-channels
310+
// feature bit was negotiated during the lifetime of the channel.
311+
SimpleTaprootFeatureBit ChannelType = 1 << 10
306312
)
307313

308314
// IsSingleFunder returns true if the channel type if one of the known single
@@ -368,6 +374,11 @@ func (c ChannelType) HasScidAliasFeature() bool {
368374
return c&ScidAliasFeatureBit == ScidAliasFeatureBit
369375
}
370376

377+
// IsTaproot returns true if the channel is using taproot features.
378+
func (c ChannelType) IsTaproot() bool {
379+
return c&SimpleTaprootFeatureBit == SimpleTaprootFeatureBit
380+
}
381+
371382
// ChannelConstraints represents a set of constraints meant to allow a node to
372383
// limit their exposure, enact flow control and ensure that all HTLCs are
373384
// economically relevant. This struct will be mirrored for both sides of the
@@ -1372,6 +1383,65 @@ func (c *OpenChannel) SecondCommitmentPoint() (*btcec.PublicKey, error) {
13721383
return input.ComputeCommitmentPoint(revocation[:]), nil
13731384
}
13741385

1386+
var (
1387+
// taprootRevRootKey is the key used to derive the revocation root for
1388+
// the taproot nonces. This is done via HMAC of the existing revocation
1389+
// root.
1390+
taprootRevRootKey = []byte("taproot-rev-root")
1391+
)
1392+
1393+
// DeriveMusig2Shachain derives a shachain producer for the taproot channel
1394+
// from normal shachain revocation root.
1395+
func DeriveMusig2Shachain(revRoot shachain.Producer) (shachain.Producer, error) { //nolint:lll
1396+
// In order to obtain the revocation root hash to create the taproot
1397+
// revocation, we'll encode the producer into a buffer, then use that
1398+
// to derive the shachain root needed.
1399+
var rootHashBuf bytes.Buffer
1400+
if err := revRoot.Encode(&rootHashBuf); err != nil {
1401+
return nil, fmt.Errorf("unable to encode producer: %w", err)
1402+
}
1403+
1404+
revRootHash := chainhash.HashH(rootHashBuf.Bytes())
1405+
1406+
// For taproot channel types, we'll also generate a distinct shachain
1407+
// root using the same seed information. We'll use this to generate
1408+
// verification nonces for the channel. We'll bind with this a simple
1409+
// hmac.
1410+
taprootRevHmac := hmac.New(sha256.New, taprootRevRootKey)
1411+
if _, err := taprootRevHmac.Write(revRootHash[:]); err != nil {
1412+
return nil, err
1413+
}
1414+
1415+
taprootRevRoot := taprootRevHmac.Sum(nil)
1416+
1417+
// Once we have the root, we can then generate our shachain producer
1418+
// and from that generate the per-commitment point.
1419+
return shachain.NewRevocationProducerFromBytes(
1420+
taprootRevRoot,
1421+
)
1422+
}
1423+
1424+
// NewMusigVerificationNonce generates the local or verification nonce for
1425+
// another musig2 session. In order to permit our implementation to not have to
1426+
// write any secret nonce state to disk, we'll use the _next_ shachain
1427+
// pre-image as our primary randomness source. When used to generate the nonce
1428+
// again to broadcast our commitment hte current height will be used.
1429+
func NewMusigVerificationNonce(pubKey *btcec.PublicKey, targetHeight uint64,
1430+
shaGen shachain.Producer) (*musig2.Nonces, error) {
1431+
1432+
// Now that we know what height we need, we'll grab the shachain
1433+
// pre-image at the target destination.
1434+
nextPreimage, err := shaGen.AtIndex(targetHeight)
1435+
if err != nil {
1436+
return nil, err
1437+
}
1438+
1439+
shaChainRand := musig2.WithCustomRand(bytes.NewBuffer(nextPreimage[:]))
1440+
pubKeyOpt := musig2.WithPublicKey(pubKey)
1441+
1442+
return musig2.GenNonces(pubKeyOpt, shaChainRand)
1443+
}
1444+
13751445
// ChanSyncMsg returns the ChannelReestablish message that should be sent upon
13761446
// reconnection with the remote peer that we're maintaining this channel with.
13771447
// The information contained within this message is necessary to re-sync our
@@ -1443,6 +1513,30 @@ func (c *OpenChannel) ChanSyncMsg() (*lnwire.ChannelReestablish, error) {
14431513
}
14441514
}
14451515

1516+
// If this is a taproot channel, then we'll need to generate our next
1517+
// verification nonce to send to the remote party. They'll use this to
1518+
// sign the next update to our commitment transaction.
1519+
var nextTaprootNonce *lnwire.Musig2Nonce
1520+
if c.ChanType.IsTaproot() {
1521+
taprootRevProducer, err := DeriveMusig2Shachain(
1522+
c.RevocationProducer,
1523+
)
1524+
if err != nil {
1525+
return nil, err
1526+
}
1527+
1528+
nextNonce, err := NewMusigVerificationNonce(
1529+
c.LocalChanCfg.MultiSigKey.PubKey,
1530+
nextLocalCommitHeight, taprootRevProducer,
1531+
)
1532+
if err != nil {
1533+
return nil, fmt.Errorf("unable to gen next "+
1534+
"nonce: %w", err)
1535+
}
1536+
1537+
nextTaprootNonce = (*lnwire.Musig2Nonce)(&nextNonce.PubNonce)
1538+
}
1539+
14461540
return &lnwire.ChannelReestablish{
14471541
ChanID: lnwire.NewChanIDFromOutPoint(
14481542
&c.FundingOutpoint,
@@ -1453,6 +1547,7 @@ func (c *OpenChannel) ChanSyncMsg() (*lnwire.ChannelReestablish, error) {
14531547
LocalUnrevokedCommitPoint: input.ComputeCommitmentPoint(
14541548
currentCommitSecret[:],
14551549
),
1550+
LocalNonce: nextTaprootNonce,
14561551
}, nil
14571552
}
14581553

@@ -3854,8 +3949,6 @@ func putChanRevocationState(chanBucket kvdb.RwBucket, channel *OpenChannel) erro
38543949
return err
38553950
}
38563951

3857-
// TODO(roasbeef): don't keep producer on disk
3858-
38593952
// If the next revocation is present, which is only the case after the
38603953
// ChannelReady message has been sent, then we'll write it to disk.
38613954
if channel.RemoteNextRevocation != nil {

channeldb/graph.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -2727,7 +2727,7 @@ func (l *LightningNode) NodeAnnouncement(signed bool) (*lnwire.NodeAnnouncement,
27272727
return nodeAnn, nil
27282728
}
27292729

2730-
sig, err := lnwire.NewSigFromRawSignature(l.AuthSigBytes)
2730+
sig, err := lnwire.NewSigFromECDSARawSignature(l.AuthSigBytes)
27312731
if err != nil {
27322732
return nil, err
27332733
}

chanrestore.go

+6
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,12 @@ func (c *chanDBRestorer) openChannelShell(backup chanbackup.Single) (
154154
chanType |= channeldb.AnchorOutputsBit
155155
chanType |= channeldb.SingleFunderTweaklessBit
156156

157+
case chanbackup.SimpleTaprootVersion:
158+
chanType = channeldb.ZeroHtlcTxFeeBit
159+
chanType |= channeldb.AnchorOutputsBit
160+
chanType |= channeldb.SingleFunderTweaklessBit
161+
chanType |= channeldb.SimpleTaprootFeatureBit
162+
157163
default:
158164
return nil, fmt.Errorf("unknown Single version: %v", err)
159165
}

cmd/lncli/cmd_open_channel.go

+8-4
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,9 @@ Signed base64 encoded PSBT or hex encoded raw wire TX (or path to file): `
5959
// of memory issues or other weird errors.
6060
psbtMaxFileSize = 1024 * 1024
6161

62-
channelTypeTweakless = "tweakless"
63-
channelTypeAnchors = "anchors"
62+
channelTypeTweakless = "tweakless"
63+
channelTypeAnchors = "anchors"
64+
channelTypeSimpleTaproot = "taproot"
6465
)
6566

6667
// TODO(roasbeef): change default number of confirmations.
@@ -253,8 +254,9 @@ var openChannelCommand = cli.Command{
253254
cli.StringFlag{
254255
Name: "channel_type",
255256
Usage: fmt.Sprintf("(optional) the type of channel to "+
256-
"propose to the remote peer (%q, %q)",
257-
channelTypeTweakless, channelTypeAnchors),
257+
"propose to the remote peer (%q, %q, %q)",
258+
channelTypeTweakless, channelTypeAnchors,
259+
channelTypeSimpleTaproot),
258260
},
259261
cli.BoolFlag{
260262
Name: "zero_conf",
@@ -443,6 +445,8 @@ func openChannel(ctx *cli.Context) error {
443445
req.CommitmentType = lnrpc.CommitmentType_STATIC_REMOTE_KEY
444446
case channelTypeAnchors:
445447
req.CommitmentType = lnrpc.CommitmentType_ANCHORS
448+
case channelTypeSimpleTaproot:
449+
req.CommitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT
446450
default:
447451
return fmt.Errorf("unsupported channel type %v", channelType)
448452
}

contractcourt/anchor_resolver.go

+14-6
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ type anchorResolver struct {
3333
// chanPoint is the channel point of the original contract.
3434
chanPoint wire.OutPoint
3535

36+
// chanType denotes the type of channel the contract belongs to.
37+
chanType channeldb.ChannelType
38+
3639
// currentReport stores the current state of the resolver for reporting
3740
// over the rpc interface.
3841
currentReport ContractReport
@@ -97,12 +100,16 @@ func (c *anchorResolver) Resolve() (ContractResolver, error) {
97100
// to the sweeper.
98101
relayFeeRate := c.Sweeper.RelayFeePerKW()
99102

103+
witnessType := input.CommitmentAnchor
104+
105+
// For taproot channels, we need to use the proper witness type.
106+
if c.chanType.IsTaproot() {
107+
witnessType = input.TaprootAnchorSweepSpend
108+
}
109+
100110
anchorInput := input.MakeBaseInput(
101-
&c.anchor,
102-
input.CommitmentAnchor,
103-
&c.anchorSignDescriptor,
104-
c.broadcastHeight,
105-
nil,
111+
&c.anchor, witnessType, &c.anchorSignDescriptor,
112+
c.broadcastHeight, nil,
106113
)
107114

108115
resultChan, err := c.Sweeper.SweepInput(
@@ -195,7 +202,8 @@ func (c *anchorResolver) IsResolved() bool {
195202
// state required for the proper resolution of a contract.
196203
//
197204
// NOTE: Part of the ContractResolver interface.
198-
func (c *anchorResolver) SupplementState(_ *channeldb.OpenChannel) {
205+
func (c *anchorResolver) SupplementState(state *channeldb.OpenChannel) {
206+
c.chanType = state.ChanType
199207
}
200208

201209
// report returns a report on the resolution state of the contract.

0 commit comments

Comments
 (0)