Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
1a488f4
chains: upgrade the keyRing instance in chainControl to a SecretKeyRing
Roasbeef Dec 10, 2018
da3625f
lnrpc: add series of new methods for exporting, recovering, and subsc…
Roasbeef Dec 10, 2018
f0e9a1f
walletunlock: exend the Init and Unlock methods to also return option…
Roasbeef Dec 10, 2018
73eb37b
peer: don't attempt to load any channels that have a non-default stat…
Roasbeef Dec 10, 2018
af4c11c
chanrestore: add new file to house chanbackup interface implementations
Roasbeef Dec 10, 2018
c5933d4
server: feed through any SCBs on start up to be restored
Roasbeef Dec 10, 2018
1d7e42a
rpc: implement new SCB related RPC calls
Roasbeef Dec 10, 2018
0b8131c
cmd/lncli: add new exportchanbackup and restorechanbackup cli commands
Roasbeef Dec 10, 2018
af1dfe1
chanbackup: add new updateBackupFile method, write fresh backup on st…
Roasbeef Feb 9, 2019
411000d
lnd: add new channelNotifier impl of chanbackup.ChannelNotifier
Roasbeef Feb 9, 2019
9512d70
config: add new backupfilepath argument for SCBs
Roasbeef Feb 9, 2019
056deca
log: hook up chanbackup logger
Roasbeef Feb 9, 2019
019ec2d
rpcserver: implement the SubscribeChannelBackups RPC method
Roasbeef Feb 9, 2019
6bc20b1
server: assemble and start chanbackup.SubSwapper on startup
Roasbeef Feb 9, 2019
d7bc93b
chanbackup: add new NilMultiSizePacked constant
Roasbeef Mar 10, 2019
7cbf032
chanbackup: extend channel backups to include entire local+remote cha…
Roasbeef Mar 10, 2019
13e7244
channeldb: also restore channel capacity in RestoreChannelShells
Roasbeef Mar 10, 2019
b93ff26
channeldb: set restored chan status within RestoreChannelShells
Roasbeef Mar 10, 2019
19ef4bb
channeldb: within AddrsForNode don't fail if no graph node is found
Roasbeef Mar 10, 2019
64b8fac
channeldb: don't read/write funding transactions if a restore channel
Roasbeef Mar 10, 2019
a508a62
lnwire: add bool types to codec for SCB format
Roasbeef Mar 10, 2019
441f010
lntest: add new initClientWhenReady to connect RPC then init client
Roasbeef Mar 10, 2019
b62dd09
lntest: exend newNode method to accept wallet password
Roasbeef Mar 10, 2019
e929142
lntest: add new Unlock method to allow unlock of fresh node
Roasbeef Mar 10, 2019
b419179
lntest: extend RestartNode to also unlock node if password is present
Roasbeef Mar 10, 2019
d9c9d6e
lntest: add new ChanBackupPath method to expose channels.backup for node
Roasbeef Mar 10, 2019
90d8a46
lnwallet: allow DLP trigger transition in ProcessChanSyncMsg if chan …
Roasbeef Mar 10, 2019
3e866c6
lnwallet: add additional comment for case in ProcessChanSyncMsg
Roasbeef Mar 10, 2019
fc8337b
lnwallet: send invalid commitment secret if restored chan in ChanSyncMsg
Roasbeef Mar 10, 2019
4ff4e1b
lnwallet: account for case where remote party has 2 unrevoked commits…
Roasbeef Mar 10, 2019
1afec13
htlcswitch: update syncChanStates for new ChanSyncMsg API
Roasbeef Mar 10, 2019
b491488
contractcourt: update to new ChanSyncMsg API, reflow comments where n…
Roasbeef Mar 10, 2019
c722f2c
contractcourt: only look for local force close for non-recovered channel
Roasbeef Mar 11, 2019
26f6fd7
contractcourt: ignore all other dispatch cases in closeObserver when …
Roasbeef Mar 11, 2019
7ab8096
lnrpc: add new VerifyChanBackup command
Roasbeef Mar 11, 2019
ead8aed
rpc: implement new VerifyChanBackup command
Roasbeef Mar 11, 2019
1f187c0
cmd/lncli: add new verifychanbackup command
Roasbeef Mar 11, 2019
26c5289
server: convert Start/Stop methods to use sync.Once
Roasbeef Mar 11, 2019
b8cbe3a
channeldb: in RestoreChannelShells don't exit if edge already exists
Roasbeef Mar 11, 2019
b451536
lntest: extend the restore/restart methods to also accept optional SCBs
Roasbeef Mar 11, 2019
ea6ed7b
test: update to new getChanPointFundingTxid
Roasbeef Mar 11, 2019
e3626d1
lntest: update to new RestoreNodeWithSeed API
Roasbeef Mar 11, 2019
acc37f7
test: refactor testDataLossProtection to extract core DLP scenario ou…
Roasbeef Mar 11, 2019
266ddba
test: add new test for streaming SCB updates
Roasbeef Mar 12, 2019
e3029de
test: add new itest for exporting SCBs
Roasbeef Mar 12, 2019
f216027
test: add new series of itests for various SCB restore scenarios
Roasbeef Mar 12, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion chainregistry.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ type chainControl struct {

signer input.Signer

keyRing keychain.KeyRing
keyRing keychain.SecretKeyRing

wc lnwallet.WalletController

Expand Down
8 changes: 5 additions & 3 deletions chanbackup/backupfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ func (b *MultiFile) UpdateAndSwap(newBackup PackedMulti) error {
return ErrNoBackupFileExists
}

log.Infof("Updating backup file at %v", b.fileName)

// If the old back up file still exists, then we'll delete it before
// proceeding.
if _, err := os.Stat(b.tempFileName); err == nil {
Expand All @@ -94,17 +96,17 @@ func (b *MultiFile) UpdateAndSwap(newBackup PackedMulti) error {
var err error
b.tempFile, err = os.Create(b.tempFileName)
if err != nil {
return err
return fmt.Errorf("unable to create temp file: %v", err)
}

// With the file created, we'll write the new packed multi backup and
// remove the temporary file all together once this method exits.
_, err = b.tempFile.Write([]byte(newBackup))
if err != nil {
return err
return fmt.Errorf("unable to write backup to temp file: %v", err)
}
if err := b.tempFile.Sync(); err != nil {
return err
return fmt.Errorf("unable to sync temp file: %v", err)
}
defer os.Remove(b.tempFileName)

Expand Down
5 changes: 5 additions & 0 deletions chanbackup/multi.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ const (
// backup. The serialized format for this version is simply: version ||
// numBackups || SCBs...
DefaultMultiVersion = 0

// NilMultiSizePacked is the size of a "nil" packed Multi (45 bytes).
// This consists of the 24 byte chacha nonce, the 16 byte MAC, one byte
// for the version, and 4 bytes to signal zero entries.
NilMultiSizePacked = 24 + 16 + 1 + 4
)

// Multi is a form of static channel backup that is amenable to being
Expand Down
82 changes: 49 additions & 33 deletions chanbackup/pubsub.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package chanbackup

import (
"bytes"
"fmt"
"net"
"sync"
"sync/atomic"
Expand Down Expand Up @@ -47,9 +48,9 @@ type ChannelEvent struct {
// ChannelSubscription represents an intent to be notified of any updates to
// the primary channel state.
type ChannelSubscription struct {
// ChanUpdates is a read-only channel that will be sent upon once the
// primary channel state is updated.
ChanUpdates <-chan ChannelEvent
// ChanUpdates is a channel that will be sent upon once the primary
// channel state is updated.
ChanUpdates chan ChannelEvent

// Cancel is a closure that allows the caller to cancel their
// subscription and free up any resources allocated.
Expand Down Expand Up @@ -160,6 +161,36 @@ func (s *SubSwapper) Stop() error {
return nil
}

// updateBackupFile updates the backup file in place given the current state of
// the SubSwapper.
func (s *SubSwapper) updateBackupFile() error {
// With our updated channel state obtained, we'll create a new multi
// from our series of singles.
var newMulti Multi
for _, backup := range s.backupState {
newMulti.StaticBackups = append(
newMulti.StaticBackups, backup,
)
}

// Now that our multi has been assembled, we'll attempt to pack
// (encrypt+encode) the new channel state to our target reader.
var b bytes.Buffer
err := newMulti.PackToWriter(&b, s.keyRing)
if err != nil {
return fmt.Errorf("unable to pack multi backup: %v", err)
}

// Finally, we'll swap out the old backup for this new one in a single
// atomic step.
err = s.Swapper.UpdateAndSwap(PackedMulti(b.Bytes()))
if err != nil {
return fmt.Errorf("unable to update multi backup: %v", err)
}

return nil
}

// backupFileUpdater is the primary goroutine of the SubSwapper which is
// responsible for listening for changes to the channel, and updating the
// persistent multi backup state with a new packed multi of the latest channel
Expand All @@ -172,6 +203,12 @@ func (s *SubSwapper) backupUpdater() {

log.Debugf("SubSwapper's backupUpdater is active!")

// Before we enter our main loop, we'll update the on-disk state with
// the latest Single state, as nodes may have new advertised addresses.
if err := s.updateBackupFile(); err != nil {
log.Errorf("Unable to refresh backup file: %v", err)
}

for {
select {
// The channel state has been modified! We'll evaluate all
Expand All @@ -183,7 +220,7 @@ func (s *SubSwapper) backupUpdater() {
// For all new open channels, we'll create a new SCB
// given the required information.
for _, newChan := range chanUpdate.NewChans {
log.Debugf("Adding chanenl %v to backup state",
log.Debugf("Adding channel %v to backup state",
newChan.FundingOutpoint)

s.backupState[newChan.FundingOutpoint] = NewSingle(
Expand All @@ -204,41 +241,20 @@ func (s *SubSwapper) backupUpdater() {

newStateSize := len(s.backupState)

// With our updated channel state obtained, we'll
// create a new multi from our series of singles.
var newMulti Multi
for _, backup := range s.backupState {
newMulti.StaticBackups = append(
newMulti.StaticBackups, backup,
)
}

// Now that our multi has been assembled, we'll attempt
// to pack (encrypt+encode) the new channel state to
// our target reader.
var b bytes.Buffer
err := newMulti.PackToWriter(&b, s.keyRing)
if err != nil {
log.Errorf("unable to pack multi backup: %v",
err)
continue
}

log.Infof("Updating on-disk multi SCB backup: "+
"num_old_chans=%v, num_new_chans=%v",
oldStateSize, newStateSize)

// Finally, we'll swap out the old backup for this new
// one in a single atomic step.
err = s.Swapper.UpdateAndSwap(
PackedMulti(b.Bytes()),
)
if err != nil {
log.Errorf("unable to update multi "+
"backup: %v", err)
continue
// With out new state constructed, we'll, atomically
// update the on-disk backup state.
if err := s.updateBackupFile(); err != nil {
log.Errorf("unable to update backup file: %v",
err)
}

// TODO(roasbeef): refresh periodically on a time basis due to
// possible addr changes from node

// Exit at once if a quit signal is detected.
case <-s.quit:
return
Expand Down
22 changes: 16 additions & 6 deletions chanbackup/pubsub_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,17 +131,23 @@ func TestSubSwapperIdempotentStartStop(t *testing.T) {

keyRing := &mockKeyRing{}

var (
swapper mockSwapper
chanNotifier mockChannelNotifier
)
var chanNotifier mockChannelNotifier

subSwapper, err := NewSubSwapper(nil, &chanNotifier, keyRing, &swapper)
swapper := newMockSwapper()
subSwapper, err := NewSubSwapper(nil, &chanNotifier, keyRing, swapper)
if err != nil {
t.Fatalf("unable to init subSwapper: %v", err)
}

subSwapper.Start()
if err := subSwapper.Start(); err != nil {
t.Fatalf("unable to start swapper: %v", err)
}

// The swapper should write the initial channel state as soon as it's
// active.
backupSet := make(map[wire.OutPoint]Single)
assertExpectedBackupSwap(t, swapper, subSwapper, keyRing, backupSet)

subSwapper.Start()

subSwapper.Stop()
Expand Down Expand Up @@ -188,6 +194,10 @@ func TestSubSwapperUpdater(t *testing.T) {
}
defer subSwapper.Stop()

// The swapper should write the initial channel state as soon as it's
// active.
assertExpectedBackupSwap(t, swapper, subSwapper, keyRing, backupSet)

// Now that the sub-swapper is active, we'll notify to add a brand new
// channel to the channel state.
newChannel, err := genRandomOpenChannelShell()
Expand Down
Loading