From bbb072e15a00b204c98f4feff7561d3ee3ea8550 Mon Sep 17 00:00:00 2001 From: Matheus Degiovani Date: Tue, 6 Feb 2024 18:19:33 -0300 Subject: [PATCH] wallet: Allow coin type upgrades on simnet This removes the enforced coin type upgrade for simnet wallets, in order to allow testing the upgrade code path under simnet. Prior to this commit, the coin type of a restored simnet wallet was always upgraded to the corresponding SLIP0044 coin type, in order to ensure that the address meant to be used as the mining address for the dcrd node was never made invalid. However, despite this enforced upgrade, there is still a bug with account and address discovery if the wallet was started before at least blocks 1 and 2 were mined in the underlying full node. To alert simnet users about this bug this commit adds a note displayed during simnet wallet creation. In the future, this bug may be fully fixed by ensuring the underlying node is fully synced and has blocks before the sync process completes. This will need to take into account use cases where the underlying node is meant to be fully unsynced (such as air-gapped wallets). --- walletsetup.go | 86 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 20 deletions(-) diff --git a/walletsetup.go b/walletsetup.go index be77db4b7..f23ca0e9b 100644 --- a/walletsetup.go +++ b/walletsetup.go @@ -18,6 +18,7 @@ import ( "decred.org/dcrwallet/v4/internal/prompt" "decred.org/dcrwallet/v4/wallet" _ "decred.org/dcrwallet/v4/wallet/drivers/bdb" + "decred.org/dcrwallet/v4/wallet/udb" "decred.org/dcrwallet/v4/walletseed" "github.com/decred/dcrd/chaincfg/v3" "github.com/decred/dcrd/dcrutil/v4" @@ -40,6 +41,68 @@ func networkDir(dataDir string, chainParams *chaincfg.Params) string { return filepath.Join(dataDir, netname) } +// displaySimnetMiningAddrs shows simnet mining addresses for the passed seed. +// If imported is false, then only the SLIP0044 address is shown (because, by +// default, the wallet is upgraded to the SLIP0044 coin type). +func displaySimnetMiningAddrs(seed []byte, imported bool) error { + params := chaincfg.SimNetParams() + ctLegacyKeyPriv, ctSLIP0044KeyPriv, acctKeyLegacyPriv, acctKeySLIP0044Priv, err := udb.HDKeysFromSeed(seed, params) + if err != nil { + return err + } + ctLegacyKeyPriv.Zero() + ctSLIP0044KeyPriv.Zero() + defer acctKeyLegacyPriv.Zero() + defer acctKeySLIP0044Priv.Zero() + + keys := map[string]*hdkeychain.ExtendedKey{ + "legacy": acctKeyLegacyPriv, + "SLIP0044": acctKeySLIP0044Priv, + } + + // If imported is false, then the wallet was created with a new random + // seed and is automatically upgraded to the SLIP0044 coin type, + // therefore the legacy key is not applicable. + if !imported { + delete(keys, "legacy") + } + + fmt.Println("") + fmt.Println("NOTE: only start the wallet after at least 2 blocks (i.e. blocks at heights 1") + fmt.Println("and 2) have been mined in the backing dcrd node, otherwise account and address") + fmt.Println("discovery may not work correctly.") + fmt.Println("") + + for _, ct := range []string{"SLIP0044", "legacy"} { + acctKeyPriv := keys[ct] + if acctKeyPriv == nil { + continue + } + xpub := acctKeyPriv.Neuter() + branch, err := xpub.Child(udb.ExternalBranch) + if err != nil { + return err + } + child, err := branch.Child(0) + if err != nil { + return err + } + + pkh := dcrutil.Hash160(child.SerializedPubKey()) + addr, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(pkh, + params) + if err != nil { + return err + } + + fmt.Printf("Mining address for the %s coin type: %s\n", ct, addr) + } + + fmt.Println("") + + 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. The bool passed back gives whether or not the wallet was @@ -105,10 +168,8 @@ func createWallet(ctx context.Context, cfg *config) error { } // Upgrade to the SLIP0044 cointype if this is a new (rather than - // user-provided) seed, and also unconditionally on simnet (to prevent - // the mining address printed below from ever becoming invalid if a - // cointype upgrade occurred later). - if !imported || cfg.SimNet { + // user-provided) seed. + if !imported { err := w.UpgradeToSLIP0044CoinType(ctx) if err != nil { return err @@ -117,25 +178,10 @@ func createWallet(ctx context.Context, cfg *config) error { // Display a mining address when creating a simnet wallet. if cfg.SimNet { - xpub, err := w.AccountXpub(ctx, 0) - if err != nil { - return err - } - branch, err := xpub.Child(0) - if err != nil { - return err - } - child, err := branch.Child(0) - if err != nil { - return err - } - pkh := dcrutil.Hash160(child.SerializedPubKey()) - addr, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(pkh, - chaincfg.SimNetParams()) + err := displaySimnetMiningAddrs(seed, imported) if err != nil { return err } - fmt.Println("Mining address:", addr) } err = loader.UnloadWallet()