@@ -40,5 +40,159 @@ BOOST_AUTO_TEST_CASE(CanProvide)
40
40
BOOST_CHECK (keyman.CanProvide (p2sh_script, data));
41
41
}
42
42
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
+
43
197
BOOST_AUTO_TEST_SUITE_END ()
44
198
} // namespace wallet
0 commit comments