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: upgradewallet fixes, improvements, test coverage #20403

Merged
merged 5 commits into from
Nov 25, 2020

Conversation

jonatack
Copy link
Member

@jonatack jonatack commented Nov 16, 2020

This follows up on #18836 and #20282 to fix and improve the as-yet unreleased upgradewallet feature and also implement review follow-up in #18836 (comment).

This PR fixes 4 upgradewallet issues:

This PR fixes the above and provides:

...user feedback to not silently return without upgrading

{
  "wallet_name": "disable private keys",
  "previous_version": 169900,
  "current_version": 169900,
  "result": "Already at latest version. Wallet version unchanged."
}

...better feedback after successfully upgrading

{
  "wallet_name": "watch-only",
  "previous_version": 159900,
  "current_version": 169900,
  "result": "Wallet upgraded successfully from version 159900 to version 169900."
}

...helpful error responses

{
  "wallet_name": "blank",
  "previous_version": 169900,
  "current_version": 169900,
  "error": "Cannot downgrade wallet from version 169900 to version 159900. Wallet version unchanged."
}
{
  "wallet_name": "blank",
  "previous_version": 130000,
  "current_version": 130000,
  "error": "Cannot upgrade a non HD split wallet from version 130000 to version 169899 without upgrading to support pre-split keypool. Please use version 169900 or no version specified."
}

updated help:

upgradewallet ( version )

Upgrade the wallet. Upgrades to the latest version if no version number is specified.
New keys may be generated and a new wallet backup will need to be made.
Arguments:
1. version    (numeric, optional, default=169900) The version number to upgrade to. Default is the latest wallet version.

Result:
{                            (json object)
  "wallet_name" : "str",     (string) Name of wallet this operation was performed on
  "previous_version" : n,    (numeric) Version of wallet before this operation
  "current_version" : n,     (numeric) Version of wallet after this operation
  "result" : "str",          (string, optional) Description of result, if no error
  "error" : "str"            (string, optional) Error message (if there is one)
}

src/wallet/wallet.cpp Outdated Show resolved Hide resolved
@achow101
Copy link
Member

Code review ACK b95925c

@DrahtBot
Copy link
Contributor

DrahtBot commented Nov 16, 2020

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

No conflicts as of last run.

@jonatack
Copy link
Member Author

Removed the cast in UpgradeWallet() per git diff b95925c 377fa31 (thanks!)

@@ -4128,7 +4128,7 @@ bool CWallet::UpgradeWallet(int& version, bilingual_str& error, std::vector<bili
     // Permanently upgrade to the version
     const WalletFeature new_version{GetClosestWalletFeature(version)};
     SetMinVersion(new_version);
-    version = static_cast<int>(new_version); // return actual updated version
+    version = new_version; // return actual updated version

@achow101
Copy link
Member

ACK 377fa31

@jonatack
Copy link
Member Author

Rebased after the merge of #20139 and addressed #20403 (comment) with 877aba8.

src/wallet/rpcwallet.cpp Outdated Show resolved Hide resolved
src/wallet/wallet.cpp Outdated Show resolved Hide resolved
@maflcko maflcko added this to the 0.21.0 milestone Nov 18, 2020
@jonatack
Copy link
Member Author

jonatack commented Nov 18, 2020

Found an edge case bug in the first commit, "wallet: enable CWallet::UpgradeWallet to return updated version", and the fix led to a simpler implementation.

Fixed two tests in the third commit, "wallet: fix and improve upgradewallet result responses"; thanks @MarcoFalke for catching one of them. The other one led to seeing the edge case bug.

Re-verified build and the wallet_upgradewallet.py test at each commit.

Diff: git diff dfec0a8 25909e6

jon@purity:~/projects/bitcoin/bitcoin (upgradewallet-improvements)$ git diff dfec0a8 25909e6
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 17631c58e7..10a7a07ee7 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -4127,15 +4127,15 @@ bool CWallet::UpgradeWallet(int& version, bilingual_str& error)
     }
 
     // Permanently upgrade to the version
-    const WalletFeature new_version{GetClosestWalletFeature(version)};
-    SetMinVersion(new_version);
-    version = new_version; // return actual updated version
+    SetMinVersion(GetClosestWalletFeature(version));
 
     for (auto spk_man : GetActiveScriptPubKeyMans()) {
         if (!spk_man->Upgrade(prev_version, version, error)) {
             return false;
         }
     }
+
+    version = GetVersion(); // return actual updated version
     return true;
 }
 
diff --git a/test/functional/wallet_upgradewallet.py b/test/functional/wallet_upgradewallet.py
index cec3dd2b6d..7cae913fa1 100755
--- a/test/functional/wallet_upgradewallet.py
+++ b/test/functional/wallet_upgradewallet.py
@@ -90,10 +90,10 @@ class UpgradeWalletTest(BitcoinTestFramework):
             v16_3_node.submitblock(b)
         assert_equal(v16_3_node.getblockcount(), to_height)
 
-    def test_upgradewallet(self, wallet, previous_version, requested_version, unchanged=False):
-        new_version = previous_version if unchanged else requested_version
+    def test_upgradewallet(self, wallet, previous_version, requested_version, expected_version=None, no_arg=False, unchanged=False):
+        new_version = previous_version if unchanged else expected_version if expected_version else requested_version
         assert_equal(wallet.getwalletinfo()["walletversion"], previous_version)
-        assert_equal(wallet.upgradewallet(requested_version),
+        assert_equal(wallet.upgradewallet() if no_arg else wallet.upgradewallet(requested_version),
             {
                 "wallet_name": "",
                 "previous_version": previous_version,
@@ -182,7 +182,7 @@ class UpgradeWalletTest(BitcoinTestFramework):
         copy_v16()
         wallet = node_master.get_wallet_rpc(self.default_wallet_name)
         self.log.info("Test upgradewallet without version arguments")
-        self.test_upgradewallet(wallet, previous_version=159900, requested_version=169900)
+        self.test_upgradewallet(wallet, previous_version=159900, requested_version=169900, no_arg=True)
         # wallet should still contain the same balance
         assert_equal(wallet.getbalance(), v16_3_balance)
 
@@ -342,7 +342,7 @@ class UpgradeWalletTest(BitcoinTestFramework):
         old_kvs = dump_bdb_kv(node_master_wallet)
         defaultkey = old_kvs[b'\x0adefaultkey']
         self.log.info("Upgrade the wallet. Should still have the same default key.")
-        self.test_upgradewallet(wallet, previous_version=139900, requested_version=169900)
+        self.test_upgradewallet(wallet, previous_version=139900, requested_version=159900, expected_version=169900)
         new_kvs = dump_bdb_kv(node_master_wallet)
         up_defaultkey = new_kvs[b'\x0adefaultkey']
         assert_equal(defaultkey, up_defaultkey)

# Upgrade the wallet. Should still have the same default key
wallet.upgradewallet(159900)
self.log.info("Upgrade the wallet. Should still have the same default key.")
self.test_upgradewallet(wallet, previous_version=139900, requested_version=159900, expected_version=169900)
Copy link
Member Author

@jonatack jonatack Nov 18, 2020

Choose a reason for hiding this comment

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

@achow101 sanity check, if current version is 139900 FEATURE_HD, and upgradewallet 159900 FEATURE_NO_DEFAULT_KEY is called, is the wallet actually upgrading to 169900 FEATURE_PRE_SPLIT_KEYPOOL/FEATURE_LATEST the expected behavior ?

Copy link
Member

@achow101 achow101 Nov 18, 2020

Choose a reason for hiding this comment

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

Versions less than FEATURE_HD_SPLIT cannot upgrade to FEATURE_HD_SPLIT or FEATURE_NO_DEFAULT_KEY. They must upgrade to FEATURE_PRE_SPLIT_KEYPOOL at which time both the previous features will also be applied.

If a user specifies FEATURE_NO_DEFAULT_KEY on FEATURE_HD wallet, we should probably give an error and tell the user they can't do that.

Edit: This test is FEATURE_HD_SPLIT, not FEATURE_HD. I'm not sure why it jumps to FEATURE_LATEST.

Copy link
Member

@achow101 achow101 Nov 18, 2020

Choose a reason for hiding this comment

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

Found it. Here's a fix.

diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index d2e1be6402..7dbbf17302 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -453,7 +453,7 @@ bool LegacyScriptPubKeyMan::Upgrade(int prev_version, int new_version, bilingual
         hd_upgrade = true;
     }
     // Upgrade to HD chain split if necessary
-    if (IsFeatureSupported(new_version, FEATURE_HD_SPLIT)) {
+    if (!IsFeatureSupported(prev_version, FEATURE_HD_SPLIT) && IsFeatureSupported(new_version, FEATURE_HD_SPLIT)) {
         WalletLogPrintf("Upgrading wallet to use HD chain split\n");
         m_storage.SetMinVersion(FEATURE_PRE_SPLIT_KEYPOOL);
         split_upgrade = FEATURE_HD_SPLIT > prev_version;
diff --git a/test/functional/wallet_upgradewallet.py b/test/functional/wallet_upgradewallet.py
index 7cae913fa1..fdd52ba574 100755
--- a/test/functional/wallet_upgradewallet.py
+++ b/test/functional/wallet_upgradewallet.py
@@ -342,7 +342,7 @@ class UpgradeWalletTest(BitcoinTestFramework):
         old_kvs = dump_bdb_kv(node_master_wallet)
         defaultkey = old_kvs[b'\x0adefaultkey']
         self.log.info("Upgrade the wallet. Should still have the same default key.")
-        self.test_upgradewallet(wallet, previous_version=139900, requested_version=159900, expected_version=169900)
+        self.test_upgradewallet(wallet, previous_version=139900, requested_version=159900, expected_version=159900)
         new_kvs = dump_bdb_kv(node_master_wallet)
         up_defaultkey = new_kvs[b'\x0adefaultkey']
         assert_equal(defaultkey, up_defaultkey)

This particular change probably needs backport to 0.21, so I'll make a separate PR for it.

src/wallet/wallet.cpp Outdated Show resolved Hide resolved
@jonatack
Copy link
Member Author

Dropped the first commit to call GetVersion() in RPCHelpMan upgradewallet().

achow101 added a commit to achow101/bitcoin that referenced this pull request Nov 18, 2020
It is unnecessary to upgrade to FEATURE_HD_SPLIT if this feature is
already supported by the wallet. Because upgrading to FEATURE_HD_SPLIT
actually requires upgrading to FEATURE_PRE_SPLIT_KEYPOOL, users would
accidentally be upgraded to FEATURE_PRE_SPLIT_KEYPOOL instead of nothing
being done.

Fixes the issue described at
bitcoin#20403 (comment)
achow101 added a commit to achow101/bitcoin that referenced this pull request Nov 18, 2020
It is unnecessary to upgrade to FEATURE_HD_SPLIT if this feature is
already supported by the wallet. Because upgrading to FEATURE_HD_SPLIT
actually requires upgrading to FEATURE_PRE_SPLIT_KEYPOOL, users would
accidentally be upgraded to FEATURE_PRE_SPLIT_KEYPOOL instead of nothing
being done.

Fixes the issue described at
bitcoin#20403 (comment)
It is unnecessary to upgrade to FEATURE_HD_SPLIT if this feature is
already supported by the wallet. Because upgrading to FEATURE_HD_SPLIT
actually requires upgrading to FEATURE_PRE_SPLIT_KEYPOOL, users would
accidentally be upgraded to FEATURE_PRE_SPLIT_KEYPOOL instead of nothing
being done.

Fixes the issue described at
bitcoin#20403 (comment)
@jonatack
Copy link
Member Author

Pulled in #20420.

@achow101
Copy link
Member

ACK 3eb6f8b

@@ -4214,7 +4214,7 @@ static RPCHelpMan sethdseed()

// Do not do anything to non-HD wallets
if (!pwallet->CanSupportFeature(FEATURE_HD)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed on a non-HD wallet. Use the upgradewallet RPC in order to upgrade a non-HD wallet to HD");
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set an HD seed on a non-HD wallet. Use the upgradewallet RPC in order to upgrade a non-HD wallet to HD");
Copy link
Member

Choose a reason for hiding this comment

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

"a" is correct...

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Member

@maflcko maflcko left a comment

Choose a reason for hiding this comment

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

review ACK 3eb6f8b 🛡

Show signature and timestamp

Signature:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

review ACK 3eb6f8b2e61c24a22ea9396d86672307845f35eb 🛡
-----BEGIN PGP SIGNATURE-----

iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p
pUin9Av/YujicGdR4qxlxmUVaSijOicvW7fTqB6MnQH6+MJnzn5mApTxTVF4ZLZj
nrHGzoEVTcnok6tsDS62eGJvmuP/FxXDZExtb/DrjMdcXqjdP4kpH67tMGAnyrnw
V/M5psoZxs/u0qm4zFa08ni6OBaeSA3U8bZ5Qj6Uk1P9of3VblGEjlw8wa3P/JU0
71s8J3wcyfXY+GS5iQ1DIbz4SgP7Ch7wLPQtgvetEPRblTvhoAgueZeURmgwHai9
ZIf1T9DpMkkBuJiZM+BhygbYF5J3r7vD0hcT/rrp3XNHpLuuMK0/ijaoJk2VXC44
/pnjQNbNXW01NH2PiamTY84rdXJW6qt7NJQtuIeOm2jivvo+Av+DOboOR5KRURUW
m4Ux1i6VaJ1Hov34Sqcnm4zy+WEq2/Lkpl5viwSOqctm7Yak/R38X5wYAx8PmsLP
S8/HSAS4aZob64D/Kkakod5VG1xl9fFw7aUQVioBGQ17hQ3PBYyXnBaIfaOiMXyR
RaovSwTo
=l1/v
-----END PGP SIGNATURE-----

Timestamp of file with hash 1140e347b1496cc50a43fa6fca8080f5ac91dbec5a7d8191668b108f5c1bf70d -

test/functional/wallet_upgradewallet.py Show resolved Hide resolved
src/wallet/rpcwallet.cpp Show resolved Hide resolved
@maflcko
Copy link
Member

maflcko commented Nov 25, 2020

Backported in #20490

sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Nov 25, 2020
@jonatack jonatack deleted the upgradewallet-improvements branch November 25, 2020 16:25
maflcko pushed a commit that referenced this pull request Nov 25, 2020
…est coverage

ca8cd89 wallet: fix and improve upgradewallet error responses (Jon Atack)
99d56e3 wallet: fix and improve upgradewallet result responses (Jon Atack)
2498b04 Don't upgrade to HD split if it is already supported (Andrew Chow)
c46c18b wallet: refactor GetClosestWalletFeature() (Jon Atack)

Pull request description:

  Github-Pull: #20403
  Rebased-From: c46c18b

  Github-Pull: #20403
  Rebased-From: 2498b04

  Github-Pull: #20403
  Rebased-From: 99d56e3

  Github-Pull: #20403
  Rebased-From: ca8cd89

Top commit has no ACKs.

Tree-SHA512: b18a1d015c963298740c585385eaa056988464112c88a519fe619be22dc78a8f6a102365cf799c50b781a77a09bec82b58ce411ab007b48f8b5de876e9c75060
janus pushed a commit to janus/bitgesell that referenced this pull request Dec 13, 2020
It is unnecessary to upgrade to FEATURE_HD_SPLIT if this feature is
already supported by the wallet. Because upgrading to FEATURE_HD_SPLIT
actually requires upgrading to FEATURE_PRE_SPLIT_KEYPOOL, users would
accidentally be upgraded to FEATURE_PRE_SPLIT_KEYPOOL instead of nothing
being done.

Fixes the issue described at
bitcoin/bitcoin#20403 (comment)
apoelstra pushed a commit to apoelstra/elements that referenced this pull request Sep 1, 2021
It is unnecessary to upgrade to FEATURE_HD_SPLIT if this feature is
already supported by the wallet. Because upgrading to FEATURE_HD_SPLIT
actually requires upgrading to FEATURE_PRE_SPLIT_KEYPOOL, users would
accidentally be upgraded to FEATURE_PRE_SPLIT_KEYPOOL instead of nothing
being done.

Fixes the issue described at
bitcoin/bitcoin#20403 (comment)

(cherry picked from commit 2498b04)
apoelstra pushed a commit to apoelstra/elements that referenced this pull request Sep 18, 2021
It is unnecessary to upgrade to FEATURE_HD_SPLIT if this feature is
already supported by the wallet. Because upgrading to FEATURE_HD_SPLIT
actually requires upgrading to FEATURE_PRE_SPLIT_KEYPOOL, users would
accidentally be upgraded to FEATURE_PRE_SPLIT_KEYPOOL instead of nothing
being done.

Fixes the issue described at
bitcoin/bitcoin#20403 (comment)

(cherry picked from commit 2498b04)
apoelstra pushed a commit to apoelstra/elements that referenced this pull request Sep 22, 2021
It is unnecessary to upgrade to FEATURE_HD_SPLIT if this feature is
already supported by the wallet. Because upgrading to FEATURE_HD_SPLIT
actually requires upgrading to FEATURE_PRE_SPLIT_KEYPOOL, users would
accidentally be upgraded to FEATURE_PRE_SPLIT_KEYPOOL instead of nothing
being done.

Fixes the issue described at
bitcoin/bitcoin#20403 (comment)

(cherry picked from commit 2498b04)
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Feb 15, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants