Merge pull request #4082 from Roasbeef/scb-anchors

chanbackup: add SCB support for anchor commitments
This commit is contained in:
Olaoluwa Osuntokun 2020-03-16 17:08:29 -07:00 committed by GitHub
commit 65f51192df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 81 additions and 26 deletions

@ -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