From 5f1e0bf7728feee3fc8c33214ccdf0b7f3f798b2 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Fri, 18 Aug 2023 17:43:47 -0700 Subject: [PATCH] multi: add new SCB version for the taproot chan type --- chanbackup/single.go | 9 +++++++++ chanrestore.go | 6 ++++++ itest/lnd_channel_backup_test.go | 30 ++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/chanbackup/single.go b/chanbackup/single.go index a9f0bea1f..ab982d59c 100644 --- a/chanbackup/single.go +++ b/chanbackup/single.go @@ -48,6 +48,10 @@ const ( // commitment and HTLC outputs that pay directly to the channel // initiator. ScriptEnforcedLeaseVersion = 4 + + // SimpleTaprootVersion is a version that denotes this channel is using + // the musig2 based taproot commitment format. + SimpleTaprootVersion = 5 ) // Single is a static description of an existing channel that can be used for @@ -213,6 +217,9 @@ func NewSingle(channel *channeldb.OpenChannel, } switch { + case channel.ChanType.IsTaproot(): + single.Version = SimpleTaprootVersion + case channel.ChanType.HasLeaseExpiration(): single.Version = ScriptEnforcedLeaseVersion single.LeaseExpiry = channel.ThawHeight @@ -244,6 +251,7 @@ func (s *Single) Serialize(w io.Writer) error { case AnchorsCommitVersion: case AnchorsZeroFeeHtlcTxCommitVersion: case ScriptEnforcedLeaseVersion: + case SimpleTaprootVersion: default: return fmt.Errorf("unable to serialize w/ unknown "+ "version: %v", s.Version) @@ -420,6 +428,7 @@ func (s *Single) Deserialize(r io.Reader) error { case AnchorsCommitVersion: case AnchorsZeroFeeHtlcTxCommitVersion: case ScriptEnforcedLeaseVersion: + case SimpleTaprootVersion: default: return fmt.Errorf("unable to de-serialize w/ unknown "+ "version: %v", s.Version) diff --git a/chanrestore.go b/chanrestore.go index c2b93070c..b8787344b 100644 --- a/chanrestore.go +++ b/chanrestore.go @@ -154,6 +154,12 @@ func (c *chanDBRestorer) openChannelShell(backup chanbackup.Single) ( chanType |= channeldb.AnchorOutputsBit chanType |= channeldb.SingleFunderTweaklessBit + case chanbackup.SimpleTaprootVersion: + chanType = channeldb.ZeroHtlcTxFeeBit + chanType |= channeldb.AnchorOutputsBit + chanType |= channeldb.SingleFunderTweaklessBit + chanType |= channeldb.SimpleTaprootFeatureBit + default: return nil, fmt.Errorf("unknown Single version: %v", err) } diff --git a/itest/lnd_channel_backup_test.go b/itest/lnd_channel_backup_test.go index ce663c6c5..10f203516 100644 --- a/itest/lnd_channel_backup_test.go +++ b/itest/lnd_channel_backup_test.go @@ -107,6 +107,13 @@ func newChanRestoreScenario(ht *lntest.HarnessTest, ct lnrpc.CommitmentType, // with a portion pushed. ht.ConnectNodes(dave, carol) + // If the commitment type is taproot, then the channel must also be + // private. + var privateChan bool + if ct == lnrpc.CommitmentType_SIMPLE_TAPROOT { + privateChan = true + } + return &chanRestoreScenario{ carol: carol, dave: dave, @@ -117,6 +124,7 @@ func newChanRestoreScenario(ht *lntest.HarnessTest, ct lnrpc.CommitmentType, PushAmt: pushAmt, ZeroConf: zeroConf, CommitmentType: ct, + Private: privateChan, }, } } @@ -564,6 +572,21 @@ func testChannelBackupRestoreCommitTypes(ht *lntest.HarnessTest) { ct: lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE, zeroConf: true, }, + + // Restore a channel back up of a taproot channel that was + // confirmed. + { + name: "restore from backup taproot", + ct: lnrpc.CommitmentType_SIMPLE_TAPROOT, + zeroConf: false, + }, + + // Restore a chanenl back up of an unconfirmed taproot channel. + { + name: "restore from backup taproot zero conf", + ct: lnrpc.CommitmentType_SIMPLE_TAPROOT, + zeroConf: true, + }, } for _, testCase := range testCases { @@ -626,6 +649,13 @@ func runChanRestoreScenarioCommitTypes(ht *lntest.HarnessTest, multi, err := ioutil.ReadFile(backupFilePath) require.NoError(ht, err) + // If this was a zero conf taproot channel, then since it's private, + // we'll need to mine an extra block (framework won't mine extra blocks + // otherwise). + if ct == lnrpc.CommitmentType_SIMPLE_TAPROOT && zeroConf { + ht.MineBlocksAndAssertNumTxes(1, 1) + } + // Now that we have Dave's backup file, we'll create a new nodeRestorer // that we'll restore using the on-disk channels.backup. restoredNodeFunc := chanRestoreViaRPC(