Add conversion from legacy keystore if it exists.
This commit is contained in:
parent
8f9f53a618
commit
b44f48882f
1 changed files with 145 additions and 6 deletions
151
walletsetup.go
151
walletsetup.go
|
@ -24,7 +24,10 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/btcsuite/btcutil/hdkeychain"
|
||||
"github.com/btcsuite/btcwallet/legacy/keystore"
|
||||
"github.com/btcsuite/btcwallet/waddrmgr"
|
||||
"github.com/btcsuite/btcwallet/walletdb"
|
||||
_ "github.com/btcsuite/btcwallet/walletdb/bdb"
|
||||
|
@ -80,7 +83,7 @@ func promptConsoleListBool(reader *bufio.Reader, prefix string, defaultEntry str
|
|||
// promptConsolePass prompts the user for a passphrase with the given prefix.
|
||||
// The function will ask the user to confirm the passphrase and will repeat
|
||||
// the prompts until they enter a matching response.
|
||||
func promptConsolePass(reader *bufio.Reader, prefix string) (string, error) {
|
||||
func promptConsolePass(reader *bufio.Reader, prefix string, confirm bool) (string, error) {
|
||||
// Prompt the user until they enter a passphrase.
|
||||
prompt := fmt.Sprintf("%s: ", prefix)
|
||||
for {
|
||||
|
@ -94,6 +97,10 @@ func promptConsolePass(reader *bufio.Reader, prefix string) (string, error) {
|
|||
continue
|
||||
}
|
||||
|
||||
if !confirm {
|
||||
return pass, nil
|
||||
}
|
||||
|
||||
fmt.Print("Confirm passphrase: ")
|
||||
confirm, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
|
@ -109,6 +116,47 @@ func promptConsolePass(reader *bufio.Reader, prefix string) (string, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// promptConsolePrivatePass prompts the user for a private passphrase with
|
||||
// varying behavior depending on whether the passed legacy keystore exists.
|
||||
// When it does, the user is prompted for the existing passphrase which is then
|
||||
// used to unlock it. On the other hand, when the legacy keystore is nil, the
|
||||
// user is prompted for a new private passphrase. All prompts are repeated
|
||||
// until the user enters a valid response.
|
||||
func promptConsolePrivatePass(reader *bufio.Reader, legacyKeyStore *keystore.Store) (string, error) {
|
||||
// When there is not an existing legacy wallet, simply prompt the user
|
||||
// for a new private passphase and return it.
|
||||
if legacyKeyStore == nil {
|
||||
return promptConsolePass(reader, "Enter the private "+
|
||||
"passphrase for your new wallet", true)
|
||||
}
|
||||
|
||||
// At this point, there is an existing legacy wallet, so prompt the user
|
||||
// for the existing private passphrase and ensure it properly unlocks
|
||||
// the legacy wallet so all of the addresses can later be imported.
|
||||
fmt.Println("You have an existing legacy wallet. All addresses from " +
|
||||
"your existing legacy wallet will be imported into the new " +
|
||||
"wallet format.")
|
||||
for {
|
||||
privPass, err := promptConsolePass(reader, "Enter the private "+
|
||||
"passphrase for your existing wallet", false)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Keep prompting the user until the passphrase is correct.
|
||||
if err := legacyKeyStore.Unlock([]byte(privPass)); err != nil {
|
||||
if err == keystore.ErrWrongPassphrase {
|
||||
fmt.Println(err)
|
||||
continue
|
||||
}
|
||||
|
||||
return "", err
|
||||
}
|
||||
|
||||
return privPass, nil
|
||||
}
|
||||
}
|
||||
|
||||
// promptConsolePublicPass prompts the user whether they want to add an
|
||||
// additional layer of encryption to the wallet. When the user answers yes and
|
||||
// there is already a public passphrase provided via the passed config, it
|
||||
|
@ -145,7 +193,7 @@ func promptConsolePublicPass(reader *bufio.Reader, privPass string, cfg *config)
|
|||
|
||||
for {
|
||||
pubPass, err = promptConsolePass(reader, "Enter the public "+
|
||||
"passphrase for your new wallet")
|
||||
"passphrase for your new wallet", true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -240,14 +288,85 @@ func promptConsoleSeed(reader *bufio.Reader) ([]byte, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// convertLegacyKeystore converts all of the addresses in the passed legacy
|
||||
// key store to the new waddrmgr.Manager format. Both the legacy keystore and
|
||||
// the new manager must be unlocked.
|
||||
func convertLegacyKeystore(legacyKeyStore *keystore.Store, manager *waddrmgr.Manager) error {
|
||||
netParams := legacyKeyStore.Net()
|
||||
blockStamp := waddrmgr.BlockStamp{
|
||||
Height: 0,
|
||||
Hash: *netParams.GenesisHash,
|
||||
}
|
||||
for _, walletAddr := range legacyKeyStore.ActiveAddresses() {
|
||||
switch addr := walletAddr.(type) {
|
||||
case keystore.PubKeyAddress:
|
||||
privKey, err := addr.PrivKey()
|
||||
if err != nil {
|
||||
fmt.Printf("WARN: Failed to obtain private key "+
|
||||
"for address %v: %v\n", addr.Address(),
|
||||
err)
|
||||
continue
|
||||
}
|
||||
|
||||
wif, err := btcutil.NewWIF((*btcec.PrivateKey)(privKey),
|
||||
netParams, addr.Compressed())
|
||||
if err != nil {
|
||||
fmt.Printf("WARN: Failed to create wallet "+
|
||||
"import format for address %v: %v\n",
|
||||
addr.Address(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = manager.ImportPrivateKey(wif, &blockStamp)
|
||||
if err != nil {
|
||||
fmt.Printf("WARN: Failed to import private "+
|
||||
"key for address %v: %v\n",
|
||||
addr.Address(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
case keystore.ScriptAddress:
|
||||
_, err := manager.ImportScript(addr.Script(), &blockStamp)
|
||||
if err != nil {
|
||||
fmt.Printf("WARN: Failed to import "+
|
||||
"pay-to-script-hash script for "+
|
||||
"address %v: %v\n", addr.Address(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
default:
|
||||
fmt.Printf("WARN: Skipping unrecognized legacy "+
|
||||
"keystore type: %T\n", addr)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// createWallet prompts the user for information needed to generate a new wallet
|
||||
// and generates the wallet accordingly. The new wallet will reside at the
|
||||
// provided path.
|
||||
func createWallet(cfg *config) error {
|
||||
// Start by prompting for the private passphrase.
|
||||
// When there is a legacy keystore, open it now to ensure any errors
|
||||
// don't end up exiting the process after the user has spent time
|
||||
// entering a bunch of information.
|
||||
netDir := networkDir(cfg.DataDir, activeNet.Params)
|
||||
keystorePath := filepath.Join(netDir, keystore.Filename)
|
||||
var legacyKeyStore *keystore.Store
|
||||
if fileExists(keystorePath) {
|
||||
var err error
|
||||
legacyKeyStore, err = keystore.OpenDir(netDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Start by prompting for the private passphrase. When there is an
|
||||
// existing keystore, the user will be promped for that passphrase,
|
||||
// otherwise they will be prompted for a new one.
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
privPass, err := promptConsolePass(reader, "Enter the private passphrase "+
|
||||
"for your new wallet")
|
||||
privPass, err := promptConsolePrivatePass(reader, legacyKeyStore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -269,7 +388,6 @@ func createWallet(cfg *config) error {
|
|||
}
|
||||
|
||||
// Create the wallet.
|
||||
netDir := networkDir(cfg.DataDir, activeNet.Params)
|
||||
dbPath := filepath.Join(netDir, walletDbName)
|
||||
fmt.Println("Creating the wallet...")
|
||||
|
||||
|
@ -290,6 +408,27 @@ func createWallet(cfg *config) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Import the addresses in the legacy keystore to the new wallet if
|
||||
// any exist.
|
||||
if legacyKeyStore != nil {
|
||||
fmt.Println("Importing addresses from existing wallet...")
|
||||
if err := manager.Unlock([]byte(privPass)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := convertLegacyKeystore(legacyKeyStore, manager); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
legacyKeyStore.Lock()
|
||||
legacyKeyStore = nil
|
||||
|
||||
// Remove the legacy key store.
|
||||
if err := os.Remove(keystorePath); err != nil {
|
||||
fmt.Printf("WARN: Failed to remove legacy wallet "+
|
||||
"from'%s'\n", keystorePath)
|
||||
}
|
||||
}
|
||||
|
||||
manager.Close()
|
||||
fmt.Println("The wallet has been created successfully.")
|
||||
return nil
|
||||
|
|
Loading…
Reference in a new issue