Skip to content

Commit 9d43447

Browse files
pinheadmzluke-jr
authored andcommitted
test: cover ScriptPubKeyMan::IsKeyActive() and Wallet::IsDestinationActive()
Github-Pull: bitcoin#27216 Rebased-From: ba65d93
1 parent 363f4bf commit 9d43447

File tree

1 file changed

+154
-0
lines changed

1 file changed

+154
-0
lines changed

src/wallet/test/scriptpubkeyman_tests.cpp

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,159 @@ BOOST_AUTO_TEST_CASE(CanProvide)
4040
BOOST_CHECK(keyman.CanProvide(p2sh_script, data));
4141
}
4242

43+
BOOST_AUTO_TEST_CASE(Legacy_IsKeyActive)
44+
{
45+
CWallet wallet(m_node.chain.get(), "", CreateMockableWalletDatabase());
46+
{
47+
LOCK(wallet.cs_wallet);
48+
wallet.SetMinVersion(FEATURE_LATEST);
49+
wallet.m_keypool_size = 10;
50+
}
51+
LegacyScriptPubKeyMan& spkm = *wallet.GetOrCreateLegacyScriptPubKeyMan();
52+
53+
// Start off empty
54+
BOOST_CHECK(spkm.GetScriptPubKeys().empty());
55+
56+
// Generate 20 keypool keys (10 internal, 10 external)
57+
{
58+
LOCK(wallet.cs_wallet);
59+
spkm.SetupGeneration();
60+
}
61+
62+
// 4 scripts per keypool key (P2PK, P2PKH, P2WPKH, P2SH-P2WPKH)
63+
// Plus 4 scripts for the seed key
64+
auto scripts1 = spkm.GetScriptPubKeys();
65+
BOOST_CHECK_EQUAL(scripts1.size(), 84);
66+
67+
// All keys are active
68+
for (const CScript& script : scripts1) {
69+
BOOST_CHECK(spkm.IsKeyActive(script));
70+
}
71+
72+
// Requesting single from spkm should not deactivate key
73+
CTxDestination dest1;
74+
{
75+
LOCK(wallet.cs_wallet);
76+
auto result = spkm.GetNewDestination(OutputType::BECH32);
77+
dest1 = result.value();
78+
}
79+
CScript script = GetScriptForDestination(dest1);
80+
BOOST_CHECK(spkm.IsKeyActive(script));
81+
82+
// Key pool size did not change
83+
auto scripts2 = spkm.GetScriptPubKeys();
84+
BOOST_CHECK_EQUAL(scripts2.size(), 84);
85+
86+
// Use key that is not the next key
87+
// (i.e. address gap in wallet recovery)
88+
{
89+
LOCK(wallet.cs_wallet);
90+
LOCK(spkm.cs_KeyStore);
91+
auto keys = spkm.MarkReserveKeysAsUsed(5);
92+
BOOST_CHECK_EQUAL(keys.size(), 4); // Because we already used one with GetNewDestination
93+
}
94+
95+
// Key pool size did not change
96+
auto scripts3 = spkm.GetScriptPubKeys();
97+
BOOST_CHECK_EQUAL(scripts3.size(), 84);
98+
99+
// All keys are still active
100+
for (const CScript& script : scripts3) {
101+
BOOST_CHECK(spkm.IsKeyActive(script));
102+
}
103+
104+
// When user encrypts wallet for the first time,
105+
// all existing keys are removed from active keypool
106+
{
107+
LOCK(wallet.cs_wallet);
108+
// called by EncryptWallet()
109+
spkm.SetupGeneration(true);
110+
}
111+
112+
// 20 new keys were added
113+
auto scripts4 = spkm.GetScriptPubKeys();
114+
BOOST_CHECK_EQUAL(scripts4.size(), 84 * 2);
115+
116+
// All 10 original keys are now inactive
117+
for (const CScript& script : scripts3) {
118+
BOOST_CHECK(!spkm.IsKeyActive(script));
119+
}
120+
}
121+
122+
BOOST_AUTO_TEST_CASE(Descriptor_IsKeyActive)
123+
{
124+
CWallet wallet(m_node.chain.get(), "", CreateMockableWalletDatabase());
125+
{
126+
LOCK(wallet.cs_wallet);
127+
wallet.LoadMinVersion(FEATURE_LATEST);
128+
wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
129+
wallet.m_keypool_size = 10;
130+
wallet.SetupDescriptorScriptPubKeyMans();
131+
}
132+
DescriptorScriptPubKeyMan* spkm = dynamic_cast<DescriptorScriptPubKeyMan*>(wallet.GetScriptPubKeyMan(OutputType::BECH32, /*internal=*/false));
133+
134+
// Start off with 10 pre-generated keys, 1 script each
135+
auto scripts1 = spkm->GetScriptPubKeys();
136+
BOOST_CHECK_EQUAL(scripts1.size(), 10);
137+
138+
// All keys are active
139+
for (const CScript& script : scripts1) {
140+
BOOST_CHECK(spkm->IsKeyActive(script));
141+
}
142+
143+
// Requesting single key from spkm should not deactivate key
144+
auto dest1 = spkm->GetNewDestination(OutputType::BECH32);
145+
CScript script = GetScriptForDestination(dest1.value());
146+
BOOST_CHECK(spkm->IsKeyActive(script));
147+
148+
// Key pool size did not change
149+
auto scripts2 = spkm->GetScriptPubKeys();
150+
BOOST_CHECK_EQUAL(scripts2.size(), 10);
151+
152+
// Use key that is not the next key
153+
// (i.e. address gap in wallet recovery)
154+
{
155+
LOCK(spkm->cs_desc_man);
156+
WalletDescriptor descriptor = spkm->GetWalletDescriptor();
157+
FlatSigningProvider provider;
158+
std::vector<CScript> scripts3;
159+
descriptor.descriptor->ExpandFromCache(/*pos=*/5, descriptor.cache, scripts3, provider);
160+
161+
BOOST_CHECK_EQUAL(scripts3.size(), 1);
162+
spkm->MarkUnusedAddresses(scripts3.front());
163+
}
164+
165+
// Key pool size increased to replace used keys
166+
auto scripts4 = spkm->GetScriptPubKeys();
167+
BOOST_CHECK_EQUAL(scripts4.size(), 16);
168+
169+
// All keys are still active
170+
for (const CScript& script : scripts4) {
171+
BOOST_CHECK(spkm->IsKeyActive(script));
172+
}
173+
174+
// When user encrypts wallet for the first time,
175+
// all existing keys are removed from active keypool
176+
{
177+
LOCK(wallet.cs_wallet);
178+
// called by EncryptWallet()
179+
wallet.SetupDescriptorScriptPubKeyMans();
180+
}
181+
182+
// This SPKM is not affected
183+
for (const CScript& script : scripts4) {
184+
BOOST_CHECK(spkm->IsKeyActive(script));
185+
}
186+
187+
// ...but at the wallet level all the keys from that SPKM are deactivated
188+
int num_script_keys_not_found = 0;
189+
for (const CScript& script : scripts4) {
190+
if (!wallet.IsDestinationActive(WitnessV0ScriptHash(script))) {
191+
++num_script_keys_not_found;
192+
}
193+
}
194+
BOOST_CHECK_EQUAL(num_script_keys_not_found, 16);
195+
}
196+
43197
BOOST_AUTO_TEST_SUITE_END()
44198
} // namespace wallet

0 commit comments

Comments
 (0)