Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wallet Recovery #1005

Merged
merged 15 commits into from
Apr 27, 2018
Merged

Wallet Recovery #1005

merged 15 commits into from
Apr 27, 2018

Conversation

cfromknecht
Copy link
Contributor

@cfromknecht cfromknecht commented Apr 3, 2018

Adds wallet recovery to lnd! These changes enable aezeeds with funds to be restored into a fresh instance, and recover any on-chain balance. Most of the rescan logic is implemented in Roasbeef/btcwallet#22, this PR involves most of the scaffolding to recovery configuration options into the wallet itself. I've added an integration test to test the recovery procedure using btcd, and I have manually tested bitcoind and neutrino.

Fixes #900

@cfromknecht cfromknecht force-pushed the wallet-recovery branch 3 times, most recently from 8ea431b to 12d7fbe Compare April 3, 2018 00:57
@zavan
Copy link

zavan commented Apr 3, 2018

Hey @cfromknecht, thanks for your work!

Is this PR ready for testing? I'd like to try it. I have deleted a wallet and recovered it from the seed, but, of course, it didn't recover the funds. I'm ready to pull and compile this, how can I trigger the rescanning process? Or should I delete my wallet and restore again?

(Using bitcoind, lnd currently @ master)

@cfromknecht cfromknecht force-pushed the wallet-recovery branch 3 times, most recently from 0ecf7be to d99607c Compare April 3, 2018 02:25
@cfromknecht
Copy link
Contributor Author

cfromknecht commented Apr 3, 2018

Hey @zavan, yep this should be ready to start testing! Please note, this will only recover on-chain funds, so nothing regarding previous channels will be restored.

I recommend restoring to a fresh directory, don't want to mangle any data you have currently. When doing lncli create you will be prompted for the seed/passwords. After doing that correctly, lncli will also prompt you for a recovery window (default 250). This should only need to be bumped if you generated a bunch of unused address, as this defines the lookahead during the rescan.

Then, wait for the node to finish syncing and you should see your total balance. If the node crashes during recovery (or you kill the process), you should be able to restart the recovery by passing a non-zero --recovery_window to lncli unlock. I recommend passing in the same recovery window used previously.

Let me know how it goes :)

@cfromknecht
Copy link
Contributor Author

FWIW, the recovery will probably take the longest when using the bitcoind backend. Currently, the logic fetches block in-order without prefetching. I have some prefetching code for btcwallet to speed that up. However, the complexity was upped a good bit because of it, so I'm gonna hold that off until a follow up PR.

@meshcollider meshcollider added wallet The wallet (lnwallet) which LND uses crypto Related to the cryptography underlying LND recovery Related to the backup/restoration of LND data (e.g. wallet seeds) labels Apr 3, 2018
chainregistry.go Outdated
// beginning of the bitcoin blockchain in case this wallet has yet to be
// created. If the wallet has already been created, this value will be
// ignored.
if walletConfig.Birthday.IsZero() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would appreciate some feedback on the correct behavior here. Other alternatives seem to be using time.Now() or just not do anything as it should be ignored.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why just not keep it Zero?

lnd.go Outdated
@@ -832,12 +850,21 @@ func genMacaroons(ctx context.Context, svc *macaroons.Service,
return nil
}

type WalletInitParams struct {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add godoc comments

lnd_test.go Outdated
AddrTypeNestedPubkeyHash = lnrpc.NewAddressRequest_NESTED_PUBKEY_HASH
)

// testOnchainFundRecovery
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fill in godoc comment

return node, nil
}

func (n *NetworkHarness) RegisterNode(node *HarnessNode) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add godoc comment

privateWalletPw, publicWalletPw, err = waitForWalletPassword(
cfg.RPCListeners, cfg.RESTListeners, serverOpts, proxyOpts,
tlsConf, macaroonService,
walletInitParams, err := waitForWalletPassword(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what will happen if --noencryptwallet is specified? Atm I don't think we even give users a seed (hence they won't be able to recover the funds), but this is not very intuitive. We should probably let a user run with --noencryptwallet and recover from a seed, or deprecate --noencryptwallet (at least on mainnet).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah we don't have rescans for unencrypted wallets, because the users don't have seeds.
currently the recovery window is initialized as 0, and can only be set when --noencryptwallet is not provided, so it will just sync as normal

if err != nil {
fmt.Println("Unable to parse recovery "+
"window: %v", err)
goto readRecoveryWindow
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

continue?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.


if len(answer) == 0 {
recoveryWindow = defaultRecoveryWindow
break readRecoveryWindow
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just break?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

}

recoveryWindow = int32(lookAhead)
break readRecoveryWindow
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

break?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Flags: []cli.Flag{
cli.IntFlag{
Name: "recovery_window",
Usage: "address lookahead for rescan",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not very clear if this will trigger a new rescan (from genesis?) if specified

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the wording to say that it will resume recovery and expand on how to properly set the value.

i guess it'd be worth also noting that this won't do anything if you're already synced, and that it's meant to be used to recover/restore onchain funds?

chainregistry.go Outdated
// beginning of the bitcoin blockchain in case this wallet has yet to be
// created. If the wallet has already been created, this value will be
// ignored.
if walletConfig.Birthday.IsZero() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why just not keep it Zero?

@cfromknecht cfromknecht force-pushed the wallet-recovery branch 5 times, most recently from 82428f3 to a8a077a Compare April 6, 2018 01:57
Copy link
Member

@Roasbeef Roasbeef left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excited to finally get this in! Performed an initial review sweep, and didn't find anything fundemental. Will now move on to testing live with a few seeds from mainnet and testnet to ensure all funds are properly recovered.

}

// Assert *HarnessNode implements the lnrpc.LightningClient interface.
var _ lnrpc.LightningClient = (*HarnessNode)(nil)
var _ lnrpc.WalletUnlockerClient = (*HarnessNode)(nil)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@Roasbeef
Copy link
Member

Needs rebase in order to trigger a fresh travis run on top of the latest changes.

@cfromknecht cfromknecht force-pushed the wallet-recovery branch 4 times, most recently from 51cf084 to 6a9d641 Compare April 18, 2018 04:21
args := ctx.Args()

// Parse the optional recovery window if it is specified. By default,
// the recovery window will be 0, indicating no lookahead should be
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some places it says it should be non-zero, here it says it can be zero. What's correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recovery window of 0 indicates no-lookahead, and no recovery will be attempted. 0 is a valid parameter, unless the user is actually trying to attempting to recover funds

lnd_test.go Outdated
// First, create a new node with strong passphrase and grab the mnemonic
// used for key derivation. This will bring up Carol with an empty
// wallet, and such that she is synced up.
password := []byte("topkek9000")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

password leak

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol

Copy link
Contributor Author

@cfromknecht cfromknecht Apr 26, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol, didn't mean to expose you ;)

@Roasbeef
Copy link
Member

After latest rebase, tested again on multiple seeds on testnet, confirmed that all funds were recovered in full! Also confirmed that if the daemon is killed mid recovery, then a start with lncli unlock --recovery_window results in a resumption of the initial rescan.

@cfromknecht cfromknecht force-pushed the wallet-recovery branch 3 times, most recently from b06ac03 to d9a9916 Compare April 25, 2018 02:41
@cfromknecht
Copy link
Contributor Author

PR has been rebased on master and includes latest btcwallet updates and unit tests for 1-in-1-out spends.

@Roasbeef
Copy link
Member

Still has a proto conflict.

@Roasbeef
Copy link
Member

With the btcwallet PR merged, this should also update the dep files during rebase as well.

@cfromknecht cfromknecht force-pushed the wallet-recovery branch 2 times, most recently from b8c00fa to 0c93cd4 Compare April 26, 2018 23:29
@cfromknecht
Copy link
Contributor Author

PR has been rebased with latest btcwallet merge! Will ping when green

@Roasbeef Roasbeef changed the title [WIP] Wallet Recovery Wallet Recovery Apr 27, 2018
Copy link
Member

@Roasbeef Roasbeef left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚡️⚡️LGTM ⚡️⚡️

@Roasbeef Roasbeef merged commit 4ab2bba into lightningnetwork:master Apr 27, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
crypto Related to the cryptography underlying LND recovery Related to the backup/restoration of LND data (e.g. wallet seeds) wallet The wallet (lnwallet) which LND uses
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants