Merge pull request #4082 from Roasbeef/scb-anchors
chanbackup: add SCB support for anchor commitments
This commit is contained in:
commit
65f51192df
@ -62,12 +62,6 @@ func FetchBackupForChan(chanPoint wire.OutPoint,
|
|||||||
return nil, fmt.Errorf("unable to find target channel")
|
return nil, fmt.Errorf("unable to find target channel")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(halseth): support chan backups for anchor types.
|
|
||||||
if targetChan.ChanType.HasAnchors() {
|
|
||||||
return nil, fmt.Errorf("channel type does not support " +
|
|
||||||
"backups yet")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Once we have the target channel, we can assemble the backup using
|
// Once we have the target channel, we can assemble the backup using
|
||||||
// the source to obtain any extra information that we may need.
|
// the source to obtain any extra information that we may need.
|
||||||
staticChanBackup, err := assembleChanBackup(chanSource, targetChan)
|
staticChanBackup, err := assembleChanBackup(chanSource, targetChan)
|
||||||
@ -93,11 +87,6 @@ func FetchStaticChanBackups(chanSource LiveChannelSource) ([]Single, error) {
|
|||||||
// channel.
|
// channel.
|
||||||
staticChanBackups := make([]Single, 0, len(openChans))
|
staticChanBackups := make([]Single, 0, len(openChans))
|
||||||
for _, openChan := range openChans {
|
for _, openChan := range openChans {
|
||||||
// TODO(halseth): support chan backups for anchor types.
|
|
||||||
if openChan.ChanType.HasAnchors() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
chanBackup, err := assembleChanBackup(chanSource, openChan)
|
chanBackup, err := assembleChanBackup(chanSource, openChan)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -213,12 +213,6 @@ func (s *SubSwapper) backupUpdater() {
|
|||||||
// For all new open channels, we'll create a new SCB
|
// For all new open channels, we'll create a new SCB
|
||||||
// given the required information.
|
// given the required information.
|
||||||
for _, newChan := range chanUpdate.NewChans {
|
for _, newChan := range chanUpdate.NewChans {
|
||||||
// TODO(halseth): support chan backups for
|
|
||||||
// anchor types.
|
|
||||||
if newChan.ChanType.HasAnchors() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("Adding channel %v to backup state",
|
log.Debugf("Adding channel %v to backup state",
|
||||||
newChan.FundingOutpoint)
|
newChan.FundingOutpoint)
|
||||||
|
|
||||||
|
@ -31,6 +31,11 @@ const (
|
|||||||
// implicitly denotes that this channel uses the new tweakless commit
|
// implicitly denotes that this channel uses the new tweakless commit
|
||||||
// format.
|
// format.
|
||||||
TweaklessCommitVersion = 1
|
TweaklessCommitVersion = 1
|
||||||
|
|
||||||
|
// AnchorsCommitVersion is the third SCB version. This version
|
||||||
|
// implicitly denotes that this channel uses the new anchor commitment
|
||||||
|
// format.
|
||||||
|
AnchorsCommitVersion = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
// Single is a static description of an existing channel that can be used for
|
// Single is a static description of an existing channel that can be used for
|
||||||
@ -157,9 +162,14 @@ func NewSingle(channel *channeldb.OpenChannel,
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if channel.ChanType.IsTweakless() {
|
switch {
|
||||||
|
case channel.ChanType.HasAnchors():
|
||||||
|
single.Version = AnchorsCommitVersion
|
||||||
|
|
||||||
|
case channel.ChanType.IsTweakless():
|
||||||
single.Version = TweaklessCommitVersion
|
single.Version = TweaklessCommitVersion
|
||||||
} else {
|
|
||||||
|
default:
|
||||||
single.Version = DefaultSingleVersion
|
single.Version = DefaultSingleVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,6 +184,7 @@ func (s *Single) Serialize(w io.Writer) error {
|
|||||||
switch s.Version {
|
switch s.Version {
|
||||||
case DefaultSingleVersion:
|
case DefaultSingleVersion:
|
||||||
case TweaklessCommitVersion:
|
case TweaklessCommitVersion:
|
||||||
|
case AnchorsCommitVersion:
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unable to serialize w/ unknown "+
|
return fmt.Errorf("unable to serialize w/ unknown "+
|
||||||
"version: %v", s.Version)
|
"version: %v", s.Version)
|
||||||
@ -332,6 +343,7 @@ func (s *Single) Deserialize(r io.Reader) error {
|
|||||||
switch s.Version {
|
switch s.Version {
|
||||||
case DefaultSingleVersion:
|
case DefaultSingleVersion:
|
||||||
case TweaklessCommitVersion:
|
case TweaklessCommitVersion:
|
||||||
|
case AnchorsCommitVersion:
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unable to de-serialize w/ unknown "+
|
return fmt.Errorf("unable to de-serialize w/ unknown "+
|
||||||
"version: %v", s.Version)
|
"version: %v", s.Version)
|
||||||
|
@ -229,12 +229,20 @@ func TestSinglePackUnpack(t *testing.T) {
|
|||||||
valid: true,
|
valid: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
// The new tweakless version, should pack/unpack with no problem.
|
// The new tweakless version, should pack/unpack with no
|
||||||
|
// problem.
|
||||||
{
|
{
|
||||||
version: TweaklessCommitVersion,
|
version: TweaklessCommitVersion,
|
||||||
valid: true,
|
valid: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// The new anchor version, should pack/unpack with no
|
||||||
|
// problem.
|
||||||
|
{
|
||||||
|
version: AnchorsCommitVersion,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
|
||||||
// A non-default version, atm this should result in a failure.
|
// A non-default version, atm this should result in a failure.
|
||||||
{
|
{
|
||||||
version: 99,
|
version: 99,
|
||||||
|
@ -106,10 +106,17 @@ func (c *chanDBRestorer) openChannelShell(backup chanbackup.Single) (
|
|||||||
case chanbackup.TweaklessCommitVersion:
|
case chanbackup.TweaklessCommitVersion:
|
||||||
chanType = channeldb.SingleFunderTweaklessBit
|
chanType = channeldb.SingleFunderTweaklessBit
|
||||||
|
|
||||||
|
case chanbackup.AnchorsCommitVersion:
|
||||||
|
chanType = channeldb.AnchorOutputsBit
|
||||||
|
chanType |= channeldb.SingleFunderTweaklessBit
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown Single version: %v", err)
|
return nil, fmt.Errorf("unknown Single version: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ltndLog.Infof("SCB Recovery: created channel shell for ChannelPoint(%v), "+
|
||||||
|
"chan_type=%v", backup.FundingOutpoint, chanType)
|
||||||
|
|
||||||
chanShell := channeldb.ChannelShell{
|
chanShell := channeldb.ChannelShell{
|
||||||
NodeAddrs: backup.Addresses,
|
NodeAddrs: backup.Addresses,
|
||||||
Chan: &channeldb.OpenChannel{
|
Chan: &channeldb.OpenChannel{
|
||||||
|
@ -19,7 +19,7 @@ type ProtocolOptions struct {
|
|||||||
|
|
||||||
// Anchors should be set if we want to support opening or accepting
|
// Anchors should be set if we want to support opening or accepting
|
||||||
// channels having the anchor commitment type.
|
// channels having the anchor commitment type.
|
||||||
Anchors bool `long:"anchors" description:"EXPERIMENTAL: enable experimental support for anchor commitments. Won't work with watchtowers or static channel backups"`
|
Anchors bool `long:"anchors" description:"EXPERIMENTAL: enable experimental support for anchor commitments, won't work with watchtowers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// LegacyOnion returns true if the old legacy onion format should be used when
|
// LegacyOnion returns true if the old legacy onion format should be used when
|
||||||
@ -35,7 +35,7 @@ func (l *ProtocolOptions) NoStaticRemoteKey() bool {
|
|||||||
return l.CommitmentTweak
|
return l.CommitmentTweak
|
||||||
}
|
}
|
||||||
|
|
||||||
// AnchorCommitments returns true if support for the the anchor commitment type
|
// AnchorCommitments returns true if support for the anchor commitment type
|
||||||
// should be signaled.
|
// should be signaled.
|
||||||
func (l *ProtocolOptions) AnchorCommitments() bool {
|
func (l *ProtocolOptions) AnchorCommitments() bool {
|
||||||
return l.Anchors
|
return l.Anchors
|
||||||
|
@ -959,11 +959,15 @@ type commitType byte
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// commitTypeLegacy is the old school commitment type.
|
// commitTypeLegacy is the old school commitment type.
|
||||||
commitTypeLegacy = iota
|
commitTypeLegacy commitType = iota
|
||||||
|
|
||||||
// commiTypeTweakless is the commitment type where the remote key is
|
// commiTypeTweakless is the commitment type where the remote key is
|
||||||
// static (non-tweaked).
|
// static (non-tweaked).
|
||||||
commitTypeTweakless
|
commitTypeTweakless
|
||||||
|
|
||||||
|
// commitTypeAnchors is the kind of commitment that has extra outputs
|
||||||
|
// used for anchoring down to commitment using CPFP.
|
||||||
|
commitTypeAnchors
|
||||||
)
|
)
|
||||||
|
|
||||||
// String returns that name of the commitment type.
|
// String returns that name of the commitment type.
|
||||||
@ -973,6 +977,8 @@ func (c commitType) String() string {
|
|||||||
return "legacy"
|
return "legacy"
|
||||||
case commitTypeTweakless:
|
case commitTypeTweakless:
|
||||||
return "tweakless"
|
return "tweakless"
|
||||||
|
case commitTypeAnchors:
|
||||||
|
return "anchors"
|
||||||
default:
|
default:
|
||||||
return "invalid"
|
return "invalid"
|
||||||
}
|
}
|
||||||
@ -985,6 +991,8 @@ func (c commitType) Args() []string {
|
|||||||
return []string{"--protocol.committweak"}
|
return []string{"--protocol.committweak"}
|
||||||
case commitTypeTweakless:
|
case commitTypeTweakless:
|
||||||
return []string{}
|
return []string{}
|
||||||
|
case commitTypeAnchors:
|
||||||
|
return []string{"--protocol.anchors"}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -8888,6 +8896,7 @@ func testDataLossProtection(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to suspend node: %v", err)
|
t.Fatalf("unable to suspend node: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return restart, chanPoint, balResp.ConfirmedBalance, nil
|
return restart, chanPoint, balResp.ConfirmedBalance, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -13986,6 +13995,10 @@ type chanRestoreTestCase struct {
|
|||||||
// confirmed or not.
|
// confirmed or not.
|
||||||
unconfirmed bool
|
unconfirmed bool
|
||||||
|
|
||||||
|
// anchorCommit is true, then the new anchor commitment type will be
|
||||||
|
// used for the channels created in the test.
|
||||||
|
anchorCommit bool
|
||||||
|
|
||||||
// restoreMethod takes an old node, then returns a function
|
// restoreMethod takes an old node, then returns a function
|
||||||
// closure that'll return the same node, but with its state
|
// closure that'll return the same node, but with its state
|
||||||
// restored via a custom method. We use this to abstract away
|
// restored via a custom method. We use this to abstract away
|
||||||
@ -14010,11 +14023,16 @@ func testChanRestoreScenario(t *harnessTest, net *lntest.NetworkHarness,
|
|||||||
|
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
|
|
||||||
|
var nodeArgs []string
|
||||||
|
if testCase.anchorCommit {
|
||||||
|
nodeArgs = commitTypeAnchors.Args()
|
||||||
|
}
|
||||||
|
|
||||||
// First, we'll create a brand new node we'll use within the test. If
|
// First, we'll create a brand new node we'll use within the test. If
|
||||||
// we have a custom backup file specified, then we'll also create that
|
// we have a custom backup file specified, then we'll also create that
|
||||||
// for use.
|
// for use.
|
||||||
dave, mnemonic, err := net.NewNodeWithSeed(
|
dave, mnemonic, err := net.NewNodeWithSeed(
|
||||||
"dave", nil, password,
|
"dave", nodeArgs, password,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create new node: %v", err)
|
t.Fatalf("unable to create new node: %v", err)
|
||||||
@ -14024,7 +14042,7 @@ func testChanRestoreScenario(t *harnessTest, net *lntest.NetworkHarness,
|
|||||||
defer func() {
|
defer func() {
|
||||||
shutdownAndAssert(net, t, dave)
|
shutdownAndAssert(net, t, dave)
|
||||||
}()
|
}()
|
||||||
carol, err := net.NewNode("carol", nil)
|
carol, err := net.NewNode("carol", nodeArgs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to make new node: %v", err)
|
t.Fatalf("unable to make new node: %v", err)
|
||||||
}
|
}
|
||||||
@ -14545,6 +14563,33 @@ func testChannelBackupRestore(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Restore the backup from the on-disk file, using the RPC
|
||||||
|
// interface, for anchor commitment channels.
|
||||||
|
{
|
||||||
|
name: "restore from backup file anchors",
|
||||||
|
initiator: true,
|
||||||
|
private: false,
|
||||||
|
anchorCommit: true,
|
||||||
|
restoreMethod: func(oldNode *lntest.HarnessNode,
|
||||||
|
backupFilePath string,
|
||||||
|
mnemonic []string) (nodeRestorer, error) {
|
||||||
|
|
||||||
|
// Read the entire Multi backup stored within
|
||||||
|
// this node's channels.backup file.
|
||||||
|
multi, err := ioutil.ReadFile(backupFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that we have Dave's backup file, we'll
|
||||||
|
// create a new nodeRestorer that will restore
|
||||||
|
// using the on-disk channels.backup.
|
||||||
|
return chanRestoreViaRPC(
|
||||||
|
net, password, mnemonic, multi,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(roasbeef): online vs offline close?
|
// TODO(roasbeef): online vs offline close?
|
||||||
|
@ -309,7 +309,7 @@ func CommitScriptAnchors(localChanCfg,
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// And the anchor spemdable by the remote node.
|
// And the anchor spendable by the remote node.
|
||||||
remoteAnchor, err := anchorScript(remoteChanCfg.MultiSigKey.PubKey)
|
remoteAnchor, err := anchorScript(remoteChanCfg.MultiSigKey.PubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
Loading…
Reference in New Issue
Block a user