Skip to content

Commit

Permalink
chanbackup: add Single.CloseTxInputs field
Browse files Browse the repository at this point in the history
The field is optional. It stores inputs needed to produce signed commit tx
using chantools scbforceclose, which calls function GetSignedCommitTx.

Pass option WithCloseTxInputs(true) to functions producing chanbackup.Single:
FetchBackupForChan, FetchStaticChanBackups, NewSubSwapper to tell them to
include CloseTxInputs into backups.
  • Loading branch information
starius committed Jan 2, 2024
1 parent 3077d92 commit 06051c9
Show file tree
Hide file tree
Showing 4 changed files with 291 additions and 7 deletions.
66 changes: 64 additions & 2 deletions chanbackup/backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,60 @@ func assembleChanBackup(addrSource AddressSource,
return &single, nil
}

func buildCloseTxInputs(targetChan *channeldb.OpenChannel) *CloseTxInputs {
log.Debugf("Crafting CloseTxInputs for ChannelPoint(%v)",
targetChan.FundingOutpoint)

localCommit := targetChan.LocalCommitment

if localCommit.CommitTx == nil {
log.Infof("CommitTx is nil for ChannelPoint(%v), "+
"skipping CloseTxInputs. This is possible when "+
"DLP is active.", targetChan.FundingOutpoint)

return nil
}

inputs := &CloseTxInputs{
CommitTx: localCommit.CommitTx,
CommitSig: localCommit.CommitSig,
}

if targetChan.ChanType.IsTaproot() {
inputs.CommitHeight = localCommit.CommitHeight
}

return inputs
}

// BackupConfig contains options of backup creation process.
type BackupConfig struct {
// Whether to put CloseTxInputs into a backup. A backup with this data
// can be used by "chantools scbforceclose" command.
includeCloseTxInputs bool
}

// BackupOption sets an option in BackupConfig.
type BackupOption func(*BackupConfig)

// WithCloseTxInputs specifies if SCB must contain inputs needed to produce
// a force close transaction from it using "chantools scbforceclose".
func WithCloseTxInputs(include bool) BackupOption {
return func(c *BackupConfig) {
c.includeCloseTxInputs = include
}
}

// FetchBackupForChan attempts to create a plaintext static channel backup for
// the target channel identified by its channel point. If we're unable to find
// the target channel, then an error will be returned.
func FetchBackupForChan(chanPoint wire.OutPoint, chanSource LiveChannelSource,
addrSource AddressSource) (*Single, error) {
addrSource AddressSource, options ...BackupOption) (*Single, error) {

var config BackupConfig
for _, opt := range options {
opt(&config)
}

// First, we'll query the channel source to see if the channel is known
// and open within the database.
Expand All @@ -75,13 +124,22 @@ func FetchBackupForChan(chanPoint wire.OutPoint, chanSource LiveChannelSource,
return nil, fmt.Errorf("unable to create chan backup: %v", err)
}

if config.includeCloseTxInputs {
staticChanBackup.CloseTxInputs = buildCloseTxInputs(targetChan)
}

return staticChanBackup, nil
}

// FetchStaticChanBackups will return a plaintext static channel back up for
// all known active/open channels within the passed channel source.
func FetchStaticChanBackups(chanSource LiveChannelSource,
addrSource AddressSource) ([]Single, error) {
addrSource AddressSource, options ...BackupOption) ([]Single, error) {

var config BackupConfig
for _, opt := range options {
opt(&config)
}

// First, we'll query the backup source for information concerning all
// currently open and available channels.
Expand All @@ -100,6 +158,10 @@ func FetchStaticChanBackups(chanSource LiveChannelSource,
return nil, err
}

if config.includeCloseTxInputs {
chanBackup.CloseTxInputs = buildCloseTxInputs(openChan)
}

staticChanBackups = append(staticChanBackups, *chanBackup)
}

Expand Down
26 changes: 23 additions & 3 deletions chanbackup/pubsub.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,24 @@ type SubSwapper struct {

quit chan struct{}
wg sync.WaitGroup

// Whether to put CloseTxInputs into a backup. A backup with this data
// can be used by "chantools scbforceclose" command.
includeCloseTxInputs bool
}

// NewSubSwapper creates a new instance of the SubSwapper given the starting
// set of channels, and the required interfaces to be notified of new channel
// updates, pack a multi backup, and swap the current best backup from its
// storage location.
func NewSubSwapper(startingChans []Single, chanNotifier ChannelNotifier,
keyRing keychain.KeyRing, backupSwapper Swapper) (*SubSwapper, error) {
keyRing keychain.KeyRing, backupSwapper Swapper,
options ...BackupOption) (*SubSwapper, error) {

var config BackupConfig
for _, opt := range options {
opt(&config)
}

// First, we'll subscribe to the latest set of channel updates given
// the set of channels we already know of.
Expand All @@ -130,6 +140,8 @@ func NewSubSwapper(startingChans []Single, chanNotifier ChannelNotifier,
keyRing: keyRing,
Swapper: backupSwapper,
quit: make(chan struct{}),

includeCloseTxInputs: config.includeCloseTxInputs,
}, nil
}

Expand Down Expand Up @@ -265,9 +277,17 @@ func (s *SubSwapper) backupUpdater() {
log.Debugf("Adding channel %v to backup state",
newChan.FundingOutpoint)

s.backupState[newChan.FundingOutpoint] = NewSingle(
newChan.OpenChannel, newChan.Addrs,
single := NewSingle(
newChan.OpenChannel,
newChan.Addrs,
)
if s.includeCloseTxInputs {
inputs := buildCloseTxInputs(
newChan.OpenChannel,
)
single.CloseTxInputs = inputs
}
s.backupState[newChan.FundingOutpoint] = single
}

// For all closed channels, we'll remove the prior
Expand Down
98 changes: 96 additions & 2 deletions chanbackup/single.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ const (
// SimpleTaprootVersion is a version that denotes this channel is using
// the musig2 based taproot commitment format.
SimpleTaprootVersion = 5

// Byte mask used that is ORed to version byte on wire indicating that
// the backup has CloseTxInputs.
closeTxVersionMask = 1 << 7
)

// Single is a static description of an existing channel that can be used for
Expand Down Expand Up @@ -138,6 +142,37 @@ type Single struct {
//
// - ScriptEnforcedLeaseVersion
LeaseExpiry uint32

// CloseTxInputs contains data needed to produce a force close tx
// using "chantools scbforceclose".
//
// The field is optional.
//
// See WithCloseTxInputs.
CloseTxInputs *CloseTxInputs
}

// CloseTxInputs contains data needed to produce a force close transaction
// using "chantools scbforceclose".
type CloseTxInputs struct {
// CommitTx is the latest version of the commitment state, broadcast
// able by us, but not signed.
// It can be signed by "chantools scbforceclose" command.
CommitTx *wire.MsgTx

// CommitSig is one half of the signature required to fully complete
// the script for the commitment transaction above. This is the
// signature signed by the remote party for our version of the
// commitment transactions.
CommitSig []byte

// CommitHeight is the update number that this ChannelDelta represents
// the total number of commitment updates to this point. This can be
// viewed as sort of a "commitment height" as this number is
// monotonically increasing.
//
// This field is filled only for taproot channels.
CommitHeight uint64
}

// NewSingle creates a new static channel backup based on an existing open
Expand Down Expand Up @@ -320,6 +355,33 @@ func (s *Single) Serialize(w io.Writer) error {
}
}

version := s.Version
if s.CloseTxInputs != nil {
version |= closeTxVersionMask

err := s.CloseTxInputs.CommitTx.Serialize(&singleBytes)
if err != nil {
return err
}

if err := lnwire.WriteElements(
&singleBytes,
uint16(len(s.CloseTxInputs.CommitSig)),
s.CloseTxInputs.CommitSig,
); err != nil {
return err
}

if s.Version == SimpleTaprootVersion {
if err := lnwire.WriteElements(
&singleBytes,
s.CloseTxInputs.CommitHeight,
); err != nil {
return err
}
}
}

// TODO(yy): remove the type assertion when we finished refactoring db
// into using write buffer.
buf, ok := w.(*bytes.Buffer)
Expand All @@ -329,7 +391,7 @@ func (s *Single) Serialize(w io.Writer) error {

return lnwire.WriteElements(
buf,
byte(s.Version),
byte(version),
uint16(len(singleBytes.Bytes())),
singleBytes.Bytes(),
)
Expand Down Expand Up @@ -420,7 +482,9 @@ func (s *Single) Deserialize(r io.Reader) error {
return err
}

s.Version = SingleBackupVersion(version)
hasCloseTx := (version & closeTxVersionMask) != 0

s.Version = SingleBackupVersion(version &^ closeTxVersionMask)

switch s.Version {
case DefaultSingleVersion:
Expand Down Expand Up @@ -533,6 +597,36 @@ func (s *Single) Deserialize(r io.Reader) error {
}
}

if hasCloseTx {
commitTx := &wire.MsgTx{}
if err := commitTx.Deserialize(r); err != nil {
return err
}

var commitSigLen uint16
if err := lnwire.ReadElement(r, &commitSigLen); err != nil {
return err
}
commitSig := make([]byte, commitSigLen)
if err := lnwire.ReadElement(r, commitSig); err != nil {
return err
}

var commitHeight uint64
if s.Version == SimpleTaprootVersion {
err := lnwire.ReadElement(r, &commitHeight)
if err != nil {
return err
}
}

s.CloseTxInputs = &CloseTxInputs{
CommitTx: commitTx,
CommitSig: commitSig,
CommitHeight: commitHeight,
}
}

return nil
}

Expand Down
Loading

0 comments on commit 06051c9

Please sign in to comment.