Skip to content

Commit 9828136

Browse files
committed
Wallet: Support disabling implicit Segwit operation
1 parent 97f7aa2 commit 9828136

File tree

8 files changed

+43
-8
lines changed

8 files changed

+43
-8
lines changed

src/dummywallet.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ void DummyWalletInit::AddWalletOptions(ArgsManager& argsman) const
4545
"-wallet=<path>",
4646
"-walletbroadcast",
4747
"-walletdir=<dir>",
48+
"-walletimplicitsegwit",
4849
"-walletnotify=<cmd>",
4950
"-walletrbf",
5051
"-dblogsize=<n>",

src/outputtype.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key)
7272
{
7373
PKHash keyid(key);
7474
CTxDestination p2pkh{keyid};
75-
if (key.IsCompressed()) {
75+
if (key.IsCompressed() && g_implicit_segwit) {
7676
CTxDestination segwit = WitnessV0KeyHash(keyid);
7777
CTxDestination p2sh = ScriptHash(GetScriptForDestination(segwit));
7878
return Vector(std::move(p2pkh), std::move(p2sh), std::move(segwit));

src/script/signingprovider.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
#include <logging.h>
1111

12+
bool g_implicit_segwit = true;
13+
1214
const SigningProvider& DUMMY_SIGNING_PROVIDER = SigningProvider();
1315

1416
template<typename M, typename K, typename V>
@@ -102,7 +104,7 @@ void FillableSigningProvider::ImplicitlyLearnRelatedKeyScripts(const CPubKey& pu
102104
// "Implicitly" refers to fact that scripts are derived automatically from
103105
// existing keys, and are present in memory, even without being explicitly
104106
// loaded (e.g. from a file).
105-
if (pubkey.IsCompressed()) {
107+
if (pubkey.IsCompressed() && g_implicit_segwit) {
106108
CScript script = GetScriptForDestination(WitnessV0KeyHash(key_id));
107109
// This does not use AddCScript, as it may be overridden.
108110
CScriptID id(script);

src/script/signingprovider.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
#include <script/script.h>
1515
#include <sync.h>
1616

17+
static const bool DEFAULT_WALLET_IMPLICIT_SEGWIT = false;
18+
19+
extern bool g_implicit_segwit;
20+
1721
struct ShortestVectorFirstComparator
1822
{
1923
bool operator()(const std::vector<unsigned char>& a, const std::vector<unsigned char>& b) const

src/wallet/init.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <node/context.h>
1515
#include <node/interface_ui.h>
1616
#include <outputtype.h>
17+
#include <script/signingprovider.h>
1718
#include <univalue.h>
1819
#include <util/check.h>
1920
#include <util/moneystr.h>
@@ -76,6 +77,7 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const
7677
argsman.AddArg("-wallet=<path>", "Specify wallet path to load at startup. Can be used multiple times to load multiple wallets. Path is to a directory containing wallet data and log files. If the path is not absolute, it is interpreted relative to <walletdir>. This only loads existing wallets and does not create new ones. For backwards compatibility this also accepts names of existing top-level data files in <walletdir>.", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::WALLET);
7778
argsman.AddArg("-walletbroadcast", strprintf("Make the wallet broadcast transactions (default: %u)", DEFAULT_WALLETBROADCAST), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
7879
argsman.AddArg("-walletdir=<dir>", "Specify directory to hold wallets (default: <datadir>/wallets if it exists, otherwise <datadir>)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::WALLET);
80+
argsman.AddArg("-walletimplicitsegwit", strprintf("Support segwit when restoring wallet backups and importing keys (default: %u)", DEFAULT_WALLET_IMPLICIT_SEGWIT), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
7981
#if HAVE_SYSTEM
8082
argsman.AddArg("-walletnotify=<cmd>", "Execute command when a wallet transaction changes. %s in cmd is replaced by TxID, %w is replaced by wallet name, %b is replaced by the hash of the block including the transaction (set to 'unconfirmed' if the transaction is not included) and %h is replaced by the block height (-1 if not included). %w is not currently implemented on windows. On systems where %w is supported, it should NOT be quoted because this would break shell escaping used to invoke the command.", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
8183
#endif
@@ -119,6 +121,13 @@ bool WalletInit::ParameterInteraction() const
119121
LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__);
120122
}
121123

124+
g_implicit_segwit = gArgs.GetBoolArg("-walletimplicitsegwit", DEFAULT_WALLET_IMPLICIT_SEGWIT);
125+
if (!g_implicit_segwit) {
126+
if (gArgs.SoftSetArg("-addresstype", "legacy")) {
127+
LogPrintf("%s: parameter interaction: -walletimplicitsegwit=%u -> setting -addresstype=legacy\n", __func__, g_implicit_segwit);
128+
}
129+
}
130+
122131
return true;
123132
}
124133

src/wallet/scriptpubkeyman.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,6 +1522,7 @@ void LegacyScriptPubKeyMan::LearnRelatedScripts(const CPubKey& key, OutputType t
15221522

15231523
void LegacyScriptPubKeyMan::LearnAllRelatedScripts(const CPubKey& key)
15241524
{
1525+
if (!g_implicit_segwit) return;
15251526
// OutputType::P2SH_SEGWIT always adds all necessary scripts for all types.
15261527
LearnRelatedScripts(key, OutputType::P2SH_SEGWIT);
15271528
}

src/wallet/test/scriptpubkeyman_tests.cpp

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,11 @@ BOOST_AUTO_TEST_CASE(CanProvide)
4040
BOOST_CHECK(keyman.CanProvide(p2sh_script, data));
4141
}
4242

43-
BOOST_AUTO_TEST_CASE(Legacy_IsKeyActive)
43+
static void legacy_IsKeyActive(const node::NodeContext& node, bool implicit_segwit)
4444
{
45-
CWallet wallet(m_node.chain.get(), "", CreateMockableWalletDatabase());
45+
const bool save_g_implicit_segwit{g_implicit_segwit};
46+
g_implicit_segwit = implicit_segwit;
47+
CWallet wallet(node.chain.get(), "", CreateMockableWalletDatabase());
4648
{
4749
LOCK(wallet.cs_wallet);
4850
wallet.SetMinVersion(FEATURE_LATEST);
@@ -61,8 +63,9 @@ BOOST_AUTO_TEST_CASE(Legacy_IsKeyActive)
6163

6264
// 4 scripts per keypool key (P2PK, P2PKH, P2WPKH, P2SH-P2WPKH)
6365
// Plus 4 scripts for the seed key
66+
// (If !implicit_segwit, P2WPKH and P2SH-P2WPKH are not generated.)
6467
auto scripts1 = spkm.GetScriptPubKeys();
65-
BOOST_CHECK_EQUAL(scripts1.size(), 84);
68+
BOOST_CHECK_EQUAL(scripts1.size(), implicit_segwit ? 84 : 42);
6669

6770
// All keys are active
6871
for (const CScript& script : scripts1) {
@@ -80,8 +83,9 @@ BOOST_AUTO_TEST_CASE(Legacy_IsKeyActive)
8083
BOOST_CHECK(spkm.IsKeyActive(script));
8184

8285
// Key pool size did not change
86+
// (If !implicit_segwit, the two segwit addresses are added back.)
8387
auto scripts2 = spkm.GetScriptPubKeys();
84-
BOOST_CHECK_EQUAL(scripts2.size(), 84);
88+
BOOST_CHECK_EQUAL(scripts2.size(), implicit_segwit ? 84 : 44);
8589

8690
// Use key that is not the next key
8791
// (i.e. address gap in wallet recovery)
@@ -94,7 +98,7 @@ BOOST_AUTO_TEST_CASE(Legacy_IsKeyActive)
9498

9599
// Key pool size did not change
96100
auto scripts3 = spkm.GetScriptPubKeys();
97-
BOOST_CHECK_EQUAL(scripts3.size(), 84);
101+
BOOST_CHECK_EQUAL(scripts3.size(), implicit_segwit ? 84 : 44);
98102

99103
// All keys are still active
100104
for (const CScript& script : scripts3) {
@@ -111,12 +115,23 @@ BOOST_AUTO_TEST_CASE(Legacy_IsKeyActive)
111115

112116
// 20 new keys were added
113117
auto scripts4 = spkm.GetScriptPubKeys();
114-
BOOST_CHECK_EQUAL(scripts4.size(), 84 * 2);
118+
BOOST_CHECK_EQUAL(scripts4.size(), (implicit_segwit ? 84 : 43) * 2);
115119

116120
// All 10 original keys are now inactive
117121
for (const CScript& script : scripts3) {
118122
BOOST_CHECK(!spkm.IsKeyActive(script));
119123
}
124+
g_implicit_segwit = save_g_implicit_segwit;
125+
}
126+
127+
BOOST_AUTO_TEST_CASE(Legacy_IsKeyActive)
128+
{
129+
legacy_IsKeyActive(m_node, /*implicit_segwit=*/true);
130+
}
131+
132+
BOOST_AUTO_TEST_CASE(Legacy_IsKeyActive_no_implicit_segwit)
133+
{
134+
legacy_IsKeyActive(m_node, /*implicit_segwit=*/false);
120135
}
121136

122137
BOOST_AUTO_TEST_CASE(Descriptor_IsKeyActive)

test/functional/test_framework/test_node.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ def __init__(self, i, datadir_path, *, chain, rpchost, timewait, timeout_factor,
129129
"--gen-suppressions=all", "--exit-on-first-error=yes",
130130
"--error-exitcode=1", "--quiet"] + self.args
131131

132+
if self.version is None:
133+
self.args.append("-walletimplicitsegwit")
134+
132135
if self.version_is_at_least(190000):
133136
self.args.append("-logthreadnames")
134137
if self.version_is_at_least(219900):

0 commit comments

Comments
 (0)