From ea7c6c3ed925cb6fa55f496e013dadcd91fd2536 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Tue, 12 Mar 2019 18:30:21 -0700 Subject: [PATCH 1/2] wallet: accept 0 bestHeight in developer environments In this commit, we fix a regression in the wallet when attempting to sync new developer test chains such as regtest and simnet. The wallet would block syncing until a block was mined, but in order to mine a block, an address must be generated by the wallet first. This address generation would block as the syncing logic was already holding the database's mutex. --- wallet/wallet.go | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/wallet/wallet.go b/wallet/wallet.go index 45fd997..e1304ee 100644 --- a/wallet/wallet.go +++ b/wallet/wallet.go @@ -450,6 +450,18 @@ func (w *Wallet) syncWithChain(birthdayStamp *waddrmgr.BlockStamp) error { return w.rescanWithTarget(addrs, unspent, nil) } +// isDevEnv determines whether the wallet is currently under a local developer +// environment, e.g. simnet or regtest. +func (w *Wallet) isDevEnv() bool { + switch uint32(w.ChainParams().Net) { + case uint32(chaincfg.RegressionNetParams.Net): + case uint32(chaincfg.SimNetParams.Net): + default: + return false + } + return true +} + // scanChain is a helper method that scans the chain from the starting height // until the tip of the chain. The onBlock callback can be used to perform // certain operations for every block that we process as we scan the chain. @@ -463,7 +475,7 @@ func (w *Wallet) scanChain(startHeight int32, // isCurrent is a helper function that we'll use to determine if the // chain backend is currently synced. When running with a btcd or - // bitcoind backend, It will use the height of the latest checkpoint as + // bitcoind backend, it will use the height of the latest checkpoint as // its lower bound. var latestCheckptHeight int32 if len(w.chainParams.Checkpoints) > 0 { @@ -471,9 +483,10 @@ func (w *Wallet) scanChain(startHeight int32, Checkpoints[len(w.chainParams.Checkpoints)-1].Height } isCurrent := func(bestHeight int32) bool { - // If the best height is zero, we assume the chain backend - // still is looking for peers to sync to. - if bestHeight == 0 { + // If the best height is zero, we assume the chain backend is + // still looking for peers to sync to in the case of a global + // network, e.g., testnet and mainnet. + if bestHeight == 0 && !w.isDevEnv() { return false } From 06bf42c746ae1b1e59b06a70be0d1d4f22806c97 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Tue, 12 Mar 2019 18:30:35 -0700 Subject: [PATCH 2/2] wallet: use last synced block as birthday in development environments In this commit, we address an issue with chains that are not current, like in the often case of regtest and simnet chains. Syncing the wallet would fail due to the chain not being current and not finding a suitable birthday block. We fix this by just using the last synced block as the birthday block to ensure we can properly sync to the chain. --- wallet/wallet.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/wallet/wallet.go b/wallet/wallet.go index e1304ee..4a9236c 100644 --- a/wallet/wallet.go +++ b/wallet/wallet.go @@ -612,13 +612,26 @@ func (w *Wallet) syncToBirthday() (*waddrmgr.BlockStamp, error) { } // If a birthday stamp has yet to be found, we'll return an error - // indicating so. - if birthdayStamp == nil { + // indicating so, but only if this is a live chain like it is the case + // with testnet and mainnet. + if birthdayStamp == nil && !w.isDevEnv() { tx.Rollback() return nil, fmt.Errorf("did not find a suitable birthday "+ "block with a timestamp greater than %v", birthday) } + // Otherwise, if we're in a development environment and we've yet to + // find a birthday block due to the chain not being current, we'll + // use the last block we've synced to as our birthday to proceed. + if birthdayStamp == nil { + syncedTo := w.Manager.SyncedTo() + err := w.Manager.SetBirthdayBlock(ns, syncedTo, true) + if err != nil { + return nil, err + } + birthdayStamp = &syncedTo + } + if err := tx.Commit(); err != nil { tx.Rollback() return nil, err