chanbackup: support backup restore of script enforced leased channels

This commit is contained in:
Wilmer Paulino 2021-07-26 13:03:00 -07:00 committed by Olaoluwa Osuntokun
parent 974fc346cf
commit 0b0dd65c93
No known key found for this signature in database
GPG key ID: 3BBD59E99B280306
3 changed files with 58 additions and 6 deletions

View file

@ -40,6 +40,13 @@ const (
// AnchorsZeroFeeHtlcTxCommitVersion is a version that denotes this // AnchorsZeroFeeHtlcTxCommitVersion is a version that denotes this
// channel is using the zero-fee second-level anchor commitment format. // channel is using the zero-fee second-level anchor commitment format.
AnchorsZeroFeeHtlcTxCommitVersion = 3 AnchorsZeroFeeHtlcTxCommitVersion = 3
// ScriptEnforcedLeaseVersion is a version that denotes this channel is
// using the zero-fee second-level anchor commitment format along with
// an additional CLTV requirement of the channel lease maturity on any
// commitment and HTLC outputs that pay directly to the channel
// initiator.
ScriptEnforcedLeaseVersion = 4
) )
// 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
@ -116,6 +123,16 @@ type Single struct {
// ShaChainRootDesc describes how to derive the private key that was // ShaChainRootDesc describes how to derive the private key that was
// used as the shachain root for this channel. // used as the shachain root for this channel.
ShaChainRootDesc keychain.KeyDescriptor ShaChainRootDesc keychain.KeyDescriptor
// LeaseExpiry represents the absolute expiration as a height of the
// chain of a channel lease that is applied to every output that pays
// directly to the channel initiator in addition to the usual CSV
// requirement.
//
// NOTE: This field will only be present for the following versions:
//
// - ScriptEnforcedLeaseVersion
LeaseExpiry uint32
} }
// NewSingle creates a new static channel backup based on an existing open // NewSingle creates a new static channel backup based on an existing open
@ -177,6 +194,10 @@ func NewSingle(channel *channeldb.OpenChannel,
} }
switch { switch {
case channel.ChanType.HasLeaseExpiration():
single.Version = ScriptEnforcedLeaseVersion
single.LeaseExpiry = channel.ThawHeight
case channel.ChanType.ZeroHtlcTxFee(): case channel.ChanType.ZeroHtlcTxFee():
single.Version = AnchorsZeroFeeHtlcTxCommitVersion single.Version = AnchorsZeroFeeHtlcTxCommitVersion
@ -203,6 +224,7 @@ func (s *Single) Serialize(w io.Writer) error {
case TweaklessCommitVersion: case TweaklessCommitVersion:
case AnchorsCommitVersion: case AnchorsCommitVersion:
case AnchorsZeroFeeHtlcTxCommitVersion: case AnchorsZeroFeeHtlcTxCommitVersion:
case ScriptEnforcedLeaseVersion:
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)
@ -264,6 +286,12 @@ func (s *Single) Serialize(w io.Writer) error {
); err != nil { ); err != nil {
return err return err
} }
if s.Version == ScriptEnforcedLeaseVersion {
err := lnwire.WriteElements(&singleBytes, s.LeaseExpiry)
if err != nil {
return err
}
}
// TODO(yy): remove the type assertion when we finished refactoring db // TODO(yy): remove the type assertion when we finished refactoring db
// into using write buffer. // into using write buffer.
@ -370,6 +398,7 @@ func (s *Single) Deserialize(r io.Reader) error {
case TweaklessCommitVersion: case TweaklessCommitVersion:
case AnchorsCommitVersion: case AnchorsCommitVersion:
case AnchorsZeroFeeHtlcTxCommitVersion: case AnchorsZeroFeeHtlcTxCommitVersion:
case ScriptEnforcedLeaseVersion:
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)
@ -463,8 +492,18 @@ func (s *Single) Deserialize(r io.Reader) error {
return err return err
} }
s.ShaChainRootDesc.KeyLocator.Family = keychain.KeyFamily(shaKeyFam) s.ShaChainRootDesc.KeyLocator.Family = keychain.KeyFamily(shaKeyFam)
err = lnwire.ReadElements(r, &s.ShaChainRootDesc.KeyLocator.Index)
if err != nil {
return err
}
return lnwire.ReadElements(r, &s.ShaChainRootDesc.KeyLocator.Index) if s.Version == ScriptEnforcedLeaseVersion {
if err := lnwire.ReadElement(r, &s.LeaseExpiry); err != nil {
return err
}
}
return nil
} }
// UnpackFromReader is similar to Deserialize method, but it expects the passed // UnpackFromReader is similar to Deserialize method, but it expects the passed

View file

@ -124,10 +124,7 @@ func genRandomOpenChannelShell() (*channeldb.OpenChannel, error) {
isInitiator = true isInitiator = true
} }
chanType := channeldb.SingleFunderBit chanType := channeldb.ChannelType(rand.Intn(8))
if rand.Int63()%2 == 0 {
chanType = channeldb.SingleFunderTweaklessBit
}
return &channeldb.OpenChannel{ return &channeldb.OpenChannel{
ChainHash: chainHash, ChainHash: chainHash,
@ -137,6 +134,7 @@ func genRandomOpenChannelShell() (*channeldb.OpenChannel, error) {
ShortChannelID: lnwire.NewShortChanIDFromInt( ShortChannelID: lnwire.NewShortChanIDFromInt(
uint64(rand.Int63()), uint64(rand.Int63()),
), ),
ThawHeight: rand.Uint32(),
IdentityPub: pub, IdentityPub: pub,
LocalChanCfg: channeldb.ChannelConfig{ LocalChanCfg: channeldb.ChannelConfig{
ChannelConstraints: channeldb.ChannelConstraints{ ChannelConstraints: channeldb.ChannelConstraints{
@ -243,6 +241,13 @@ func TestSinglePackUnpack(t *testing.T) {
valid: true, valid: true,
}, },
// The new script enforced channel lease version should
// pack/unpack with no problem.
{
version: ScriptEnforcedLeaseVersion,
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,
@ -293,8 +298,9 @@ func TestSinglePackUnpack(t *testing.T) {
t.Fatalf("unable to serialize single: %v", err) t.Fatalf("unable to serialize single: %v", err)
} }
// Mutate the version byte to an unknown version.
rawBytes := rawSingle.Bytes() rawBytes := rawSingle.Bytes()
rawBytes[0] ^= 5 rawBytes[0] = ^uint8(0)
newReader := bytes.NewReader(rawBytes) newReader := bytes.NewReader(rawBytes)
err = unpackedSingle.Deserialize(newReader) err = unpackedSingle.Deserialize(newReader)

View file

@ -149,6 +149,12 @@ func (c *chanDBRestorer) openChannelShell(backup chanbackup.Single) (
chanType |= channeldb.AnchorOutputsBit chanType |= channeldb.AnchorOutputsBit
chanType |= channeldb.SingleFunderTweaklessBit chanType |= channeldb.SingleFunderTweaklessBit
case chanbackup.ScriptEnforcedLeaseVersion:
chanType = channeldb.LeaseExpirationBit
chanType |= channeldb.ZeroHtlcTxFeeBit
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)
} }
@ -172,6 +178,7 @@ func (c *chanDBRestorer) openChannelShell(backup chanbackup.Single) (
RemoteCurrentRevocation: backup.RemoteNodePub, RemoteCurrentRevocation: backup.RemoteNodePub,
RevocationStore: shachain.NewRevocationStore(), RevocationStore: shachain.NewRevocationStore(),
RevocationProducer: shaChainProducer, RevocationProducer: shaChainProducer,
ThawHeight: backup.LeaseExpiry,
}, },
} }