1 // Copyright (c) 2019-2022 The Limenka developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 5 #ifndef LIMENKA_WALLET_SCRIPTPUBKEYMAN_H
6 #define LIMENKA_WALLET_SCRIPTPUBKEYMAN_H
7 8 #include <addresstype.h>
9 #include <common/messages.h>
10 #include <common/signmessage.h>
11 #include <common/types.h>
12 #include <logging.h>
13 #include <node/types.h>
14 #include <psbt.h>
15 #include <script/descriptor.h>
16 #include <script/script.h>
17 #include <script/signingprovider.h>
18 #include <util/result.h>
19 #include <util/time.h>
20 #include <wallet/crypter.h>
21 #include <wallet/types.h>
22 #include <wallet/walletdb.h>
23 #include <wallet/walletutil.h>
24 25 #include <boost/signals2/signal.hpp>
26 27 #include <functional>
28 #include <optional>
29 #include <unordered_map>
30 31 enum class OutputType;
32 33 namespace wallet {
34 struct MigrationData;
35 class ScriptPubKeyMan;
36 37 // Wallet storage things that ScriptPubKeyMans need in order to be able to store things to the wallet database.
38 // It provides access to things that are part of the entire wallet and not specific to a ScriptPubKeyMan such as
39 // wallet flags, wallet version, encryption keys, encryption status, and the database itself. This allows a
40 // ScriptPubKeyMan to have callbacks into CWallet without causing a circular dependency.
41 // WalletStorage should be the same for all ScriptPubKeyMans of a wallet.
42 class WalletStorage
43 {
44 public:
45 virtual ~WalletStorage() = default;
46 virtual std::string GetDisplayName() const = 0;
47 virtual WalletDatabase& GetDatabase() const = 0;
48 virtual bool IsWalletFlagSet(uint64_t) const = 0;
49 virtual void UnsetBlankWalletFlag(WalletBatch&) = 0;
50 virtual bool CanSupportFeature(enum WalletFeature) const = 0;
51 virtual void SetMinVersion(enum WalletFeature, WalletBatch* = nullptr) = 0;
52 //! Pass the encryption key to cb().
53 virtual bool WithEncryptionKey(std::function<bool (const CKeyingMaterial&)> cb) const = 0;
54 virtual bool HasEncryptionKeys() const = 0;
55 virtual bool IsLocked() const = 0;
56 //! Callback function for after TopUp completes containing any scripts that were added by a SPKMan
57 virtual void TopUpCallback(const std::set<CScript>&, ScriptPubKeyMan*) = 0;
58 };
59 60 //! Constant representing an unknown spkm creation time
61 static constexpr int64_t UNKNOWN_TIME = std::numeric_limits<int64_t>::max();
62 63 //! Default for -keypool
64 static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
65 66 std::vector<CKeyID> GetAffectedKeys(const CScript& spk, const SigningProvider& provider);
67 68 /** A key from a CWallet's keypool
69 *
70 * The wallet holds one (for pre HD-split wallets) or several keypools. These
71 * are sets of keys that have not yet been used to provide addresses or receive
72 * change.
73 *
74 * The Limenka wallet was originally a collection of unrelated private
75 * keys with their associated addresses. If a non-HD wallet generated a
76 * key/address, gave that address out and then restored a backup from before
77 * that key's generation, then any funds sent to that address would be
78 * lost definitively.
79 *
80 * The keypool was implemented to avoid this scenario (commit: 10384941). The
81 * wallet would generate a set of keys (100 by default). When a new public key
82 * was required, either to give out as an address or to use in a change output,
83 * it would be drawn from the keypool. The keypool would then be topped up to
84 * maintain 100 keys. This ensured that as long as the wallet hadn't used more
85 * than 100 keys since the previous backup, all funds would be safe, since a
86 * restored wallet would be able to scan for all owned addresses.
87 *
88 * A keypool also allowed encrypted wallets to give out addresses without
89 * having to be decrypted to generate a new private key.
90 *
91 * With the introduction of HD wallets (commit: f1902510), the keypool
92 * essentially became an address look-ahead pool. Restoring old backups can no
93 * longer definitively lose funds as long as the addresses used were from the
94 * wallet's HD seed (since all private keys can be rederived from the seed).
95 * However, if many addresses were used since the backup, then the wallet may
96 * not know how far ahead in the HD chain to look for its addresses. The
97 * keypool is used to implement a 'gap limit'. The keypool maintains a set of
98 * keys (by default 1000) ahead of the last used key and scans for the
99 * addresses of those keys. This avoids the risk of not seeing transactions
100 * involving the wallet's addresses, or of re-using the same address.
101 * In the unlikely case where none of the addresses in the `gap limit` are
102 * used on-chain, the look-ahead will not be incremented to keep
103 * a constant size and addresses beyond this range will not be detected by an
104 * old backup. For this reason, it is not recommended to decrease keypool size
105 * lower than default value.
106 *
107 * The HD-split wallet feature added a second keypool (commit: 02592f4c). There
108 * is an external keypool (for addresses to hand out) and an internal keypool
109 * (for change addresses).
110 *
111 * Keypool keys are stored in the wallet/keystore's keymap. The keypool data is
112 * stored as sets of indexes in the wallet (setInternalKeyPool,
113 * setExternalKeyPool and set_pre_split_keypool), and a map from the key to the
114 * index (m_pool_key_to_index). The CKeyPool object is used to
115 * serialize/deserialize the pool data to/from the database.
116 */
117 class CKeyPool
118 {
119 public:
120 //! The time at which the key was generated. Set in AddKeypoolPubKeyWithDB
121 int64_t nTime;
122 //! The public key
123 CPubKey vchPubKey;
124 //! Whether this keypool entry is in the internal keypool (for change outputs)
125 bool fInternal;
126 //! Whether this key was generated for a keypool before the wallet was upgraded to HD-split
127 bool m_pre_split;
128 129 CKeyPool();
130 CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn);
131 132 template<typename Stream>
133 void Serialize(Stream& s) const
134 {
135 s << int{259900}; // Unused field, writes the highest client version ever written
136 s << nTime << vchPubKey << fInternal << m_pre_split;
137 }
138 139 template<typename Stream>
140 void Unserialize(Stream& s)
141 {
142 s >> int{}; // Discard unused field
143 s >> nTime >> vchPubKey;
144 try {
145 s >> fInternal;
146 } catch (std::ios_base::failure&) {
147 /* flag as external address if we can't read the internal boolean
148 (this will be the case for any wallet before the HD chain split version) */
149 fInternal = false;
150 }
151 try {
152 s >> m_pre_split;
153 } catch (std::ios_base::failure&) {
154 /* flag as postsplit address if we can't read the m_pre_split boolean
155 (this will be the case for any wallet that upgrades to HD chain split) */
156 m_pre_split = false;
157 }
158 }
159 };
160 161 struct WalletDestination
162 {
163 CTxDestination dest;
164 std::optional<bool> internal;
165 };
166 167 /*
168 * A class implementing ScriptPubKeyMan manages some (or all) scriptPubKeys used in a wallet.
169 * It contains the scripts and keys related to the scriptPubKeys it manages.
170 * A ScriptPubKeyMan will be able to give out scriptPubKeys to be used, as well as marking
171 * when a scriptPubKey has been used. It also handles when and how to store a scriptPubKey
172 * and its related scripts and keys, including encryption.
173 */
174 class ScriptPubKeyMan
175 {
176 protected:
177 WalletStorage& m_storage;
178 179 SigningResult SignMessageBIP322(MessageSignatureFormat format, const SigningProvider* keystore, const std::string& message, const CTxDestination& address, std::string& str_sig) const;
180 181 public:
182 explicit ScriptPubKeyMan(WalletStorage& storage) : m_storage(storage) {}
183 virtual ~ScriptPubKeyMan() = default;
184 virtual util::Result<CTxDestination> GetNewDestination(const OutputType type) { return util::Error{Untranslated("Not supported")}; }
185 virtual isminetype IsMine(const CScript& script) const { return ISMINE_NO; }
186 187 //! Check that the given decryption key is valid for this ScriptPubKeyMan, i.e. it decrypts all of the keys handled by it.
188 virtual bool CheckDecryptionKey(const CKeyingMaterial& master_key) { return false; }
189 virtual bool Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch) { return false; }
190 191 virtual util::Result<CTxDestination> GetReservedDestination(const OutputType type, bool internal, int64_t& index, CKeyPool& keypool) { return util::Error{Untranslated("Not supported")}; }
192 virtual void KeepDestination(int64_t index, const OutputType& type) {}
193 virtual void ReturnDestination(int64_t index, bool internal, const CTxDestination& addr) {}
194 195 /** Fills internal address pool. Use within ScriptPubKeyMan implementations should be used sparingly and only
196 * when something from the address pool is removed, excluding GetNewDestination and GetReservedDestination.
197 * External wallet code is primarily responsible for topping up prior to fetching new addresses
198 */
199 virtual bool TopUp(unsigned int size = 0) { return false; }
200 201 /** Mark unused addresses as being used
202 * Affects all keys up to and including the one determined by provided script.
203 *
204 * @param script determines the last key to mark as used
205 *
206 * @return All of the addresses affected
207 */
208 virtual std::vector<WalletDestination> MarkUnusedAddresses(const CScript& script) { return {}; }
209 210 /* Determines if address is derived from active key manager */
211 virtual bool IsKeyActive(const CScript& script) const = 0;
212 213 /** Sets up the key generation stuff, i.e. generates new HD seeds and sets them as active.
214 * Returns false if already setup or setup fails, true if setup is successful
215 * Set force=true to make it re-setup if already setup, used for upgrades
216 */
217 virtual bool SetupGeneration(bool force = false) { return false; }
218 219 /* Returns true if HD is enabled */
220 virtual bool IsHDEnabled() const { return false; }
221 222 /* Returns true if the wallet can give out new addresses. This means it has keys in the keypool or can generate new keys */
223 virtual bool CanGetAddresses(bool internal = false) const { return false; }
224 225 /** Upgrades the wallet to the specified version */
226 virtual bool Upgrade(int prev_version, int new_version, bilingual_str& error) { return true; }
227 228 virtual bool HavePrivateKeys() const { return false; }
229 virtual bool HaveCryptedKeys() const { return false; }
230 231 //! The action to do when the DB needs rewrite
232 virtual void RewriteDB() {}
233 234 virtual std::optional<int64_t> GetOldestKeyPoolTime() const { return GetTime(); }
235 236 virtual unsigned int GetKeyPoolSize() const { return 0; }
237 238 virtual int64_t GetTimeFirstKey() const { return 0; }
239 240 virtual std::unique_ptr<CKeyMetadata> GetMetadata(const CTxDestination& dest) const { return nullptr; }
241 242 virtual std::unique_ptr<SigningProvider> GetSolvingProvider(const CScript& script) const { return nullptr; }
243 244 /** Whether this ScriptPubKeyMan can provide a SigningProvider (via GetSolvingProvider) that, combined with
245 * sigdata, can produce solving data.
246 */
247 virtual bool CanProvide(const CScript& script, SignatureData& sigdata) { return false; }
248 249 /** Creates new signatures and adds them to the transaction. Returns whether all inputs were signed */
250 virtual bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors, std::optional<CAmount>* inputs_amount_sum = nullptr) const { return false; }
251 /** Sign a message with the given script */
252 virtual SigningResult SignMessage(const MessageSignatureFormat format, const std::string& message, const CTxDestination& address, std::string& str_sig) const { return SigningResult::SIGNING_FAILED; };
253 /** Adds script and derivation path information to a PSBT, and optionally signs it. */
254 virtual std::optional<common::PSBTError> FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = SIGHASH_DEFAULT, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const { return common::PSBTError::UNSUPPORTED; }
255 256 virtual uint256 GetID() const { return uint256(); }
257 258 /** Returns a set of all the scriptPubKeys that this ScriptPubKeyMan watches */
259 virtual std::unordered_set<CScript, SaltedSipHasher> GetScriptPubKeys() const { return {}; };
260 261 /** Prepends the wallet name in logging output to ease debugging in multi-wallet use cases */
262 template <typename... Params>
263 void WalletLogPrintf(util::ConstevalFormatString<sizeof...(Params)> wallet_fmt, const Params&... params) const
264 {
265 LogInfo("%s %s", m_storage.GetDisplayName(), tfm::format(wallet_fmt, params...));
266 };
267 268 /** Watch-only address added */
269 boost::signals2::signal<void (bool fHaveWatchOnly)> NotifyWatchonlyChanged;
270 271 /** Keypool has new keys */
272 boost::signals2::signal<void ()> NotifyCanGetAddressesChanged;
273 274 /** Birth time changed */
275 boost::signals2::signal<void (const ScriptPubKeyMan* spkm, int64_t new_birth_time)> NotifyFirstKeyTimeChanged;
276 };
277 278 /** OutputTypes supported by the LegacyScriptPubKeyMan */
279 static const std::unordered_set<OutputType> LEGACY_OUTPUT_TYPES {
280 OutputType::LEGACY,
281 OutputType::P2SH_SEGWIT,
282 OutputType::BECH32,
283 };
284 285 class DescriptorScriptPubKeyMan;
286 287 // Manages the data for a LegacyScriptPubKeyMan.
288 // This is the minimum necessary to load a legacy wallet so that it can be migrated.
289 class LegacyDataSPKM : public ScriptPubKeyMan, public FillableSigningProvider
290 {
291 protected:
292 using WatchOnlySet = std::set<CScript>;
293 using WatchKeyMap = std::map<CKeyID, CPubKey>;
294 using CryptedKeyMap = std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char>>>;
295 296 CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore);
297 WatchOnlySet setWatchOnly GUARDED_BY(cs_KeyStore);
298 WatchKeyMap mapWatchKeys GUARDED_BY(cs_KeyStore);
299 300 /* the HD chain data model (external chain counters) */
301 CHDChain m_hd_chain;
302 std::unordered_map<CKeyID, CHDChain, SaltedSipHasher> m_inactive_hd_chains;
303 304 //! keeps track of whether Unlock has run a thorough check before
305 bool fDecryptionThoroughlyChecked = true;
306 307 bool AddWatchOnlyInMem(const CScript &dest);
308 virtual bool AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey);
309 bool AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
310 311 // Helper function to retrieve a conservative superset of all output scripts that may be relevant to this LegacyDataSPKM.
312 // It may include scripts that are invalid or not actually watched by this LegacyDataSPKM.
313 // Used only in migration.
314 std::unordered_set<CScript, SaltedSipHasher> GetCandidateScriptPubKeys() const;
315 public:
316 using ScriptPubKeyMan::ScriptPubKeyMan;
317 318 // Map from Key ID to key metadata.
319 std::map<CKeyID, CKeyMetadata> mapKeyMetadata GUARDED_BY(cs_KeyStore);
320 321 // Map from Script ID to key metadata (for watch-only keys).
322 std::map<CScriptID, CKeyMetadata> m_script_metadata GUARDED_BY(cs_KeyStore);
323 324 // ScriptPubKeyMan overrides
325 bool CheckDecryptionKey(const CKeyingMaterial& master_key) override;
326 [[nodiscard]] bool IsKeyActive(const CScript& script) const override;
327 std::unordered_set<CScript, SaltedSipHasher> GetScriptPubKeys() const override;
328 std::unique_ptr<SigningProvider> GetSolvingProvider(const CScript& script) const override;
329 uint256 GetID() const override { return uint256::ONE; }
330 // TODO: Remove IsMine when deleting LegacyScriptPubKeyMan
331 isminetype IsMine(const CScript& script) const override;
332 bool CanProvide(const CScript& script, SignatureData& sigdata) override;
333 334 // FillableSigningProvider overrides
335 bool HaveKey(const CKeyID &address) const override;
336 bool GetKey(const CKeyID &address, CKey& keyOut) const override;
337 bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
338 bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
339 340 std::set<int64_t> setInternalKeyPool GUARDED_BY(cs_KeyStore);
341 std::set<int64_t> setExternalKeyPool GUARDED_BY(cs_KeyStore);
342 std::set<int64_t> set_pre_split_keypool GUARDED_BY(cs_KeyStore);
343 int64_t m_max_keypool_index GUARDED_BY(cs_KeyStore) = 0;
344 std::map<CKeyID, int64_t> m_pool_key_to_index;
345 346 //! Load metadata (used by LoadWallet)
347 virtual void LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &metadata);
348 virtual void LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &metadata);
349 350 //! Adds a watch-only address to the store, without saving it to disk (used by LoadWallet)
351 bool LoadWatchOnly(const CScript &dest);
352 //! Returns whether the watch-only script is in the wallet
353 bool HaveWatchOnly(const CScript &dest) const;
354 //! Returns whether there are any watch-only things in the wallet
355 bool HaveWatchOnly() const;
356 //! Adds a key to the store, without saving it to disk (used by LoadWallet)
357 bool LoadKey(const CKey& key, const CPubKey &pubkey);
358 //! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
359 bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret, bool checksum_valid);
360 //! Adds a CScript to the store
361 bool LoadCScript(const CScript& redeemScript);
362 //! Load a HD chain model (used by LoadWallet)
363 void LoadHDChain(const CHDChain& chain);
364 void AddInactiveHDChain(const CHDChain& chain);
365 const CHDChain& GetHDChain() const { return m_hd_chain; }
366 //! Load a keypool entry
367 void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool);
368 369 //! Fetches a pubkey from mapWatchKeys if it exists there
370 bool GetWatchPubKey(const CKeyID &address, CPubKey &pubkey_out) const;
371 372 /**
373 * Retrieves scripts that were imported by bugs into the legacy spkm and are
374 * simply invalid, such as a sh(sh(pkh())) script, or not watched.
375 */
376 std::unordered_set<CScript, SaltedSipHasher> GetNotMineScriptPubKeys() const;
377 378 /** Get the DescriptorScriptPubKeyMans (with private keys) that have the same scriptPubKeys as this LegacyScriptPubKeyMan.
379 * Does not modify this ScriptPubKeyMan. */
380 std::optional<MigrationData> MigrateToDescriptor();
381 /** Delete all the records of this LegacyScriptPubKeyMan from disk*/
382 bool DeleteRecords();
383 bool DeleteRecordsWithDB(WalletBatch& batch);
384 };
385 386 // Implements the full legacy wallet behavior
387 class LegacyScriptPubKeyMan : public LegacyDataSPKM
388 {
389 private:
390 WalletBatch *encrypted_batch GUARDED_BY(cs_KeyStore) = nullptr;
391 392 // By default, do not scan any block until keys/scripts are generated/imported
393 int64_t nTimeFirstKey GUARDED_BY(cs_KeyStore) = UNKNOWN_TIME;
394 395 //! Number of pre-generated keys/scripts (part of the look-ahead process, used to detect payments)
396 int64_t m_keypool_size GUARDED_BY(cs_KeyStore){DEFAULT_KEYPOOL_SIZE};
397 398 bool AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey) override;
399 400 /**
401 * Private version of AddWatchOnly method which does not accept a
402 * timestamp, and which will reset the wallet's nTimeFirstKey value to 1 if
403 * the watch key did not previously have a timestamp associated with it.
404 * Because this is an inherited virtual method, it is accessible despite
405 * being marked private, but it is marked private anyway to encourage use
406 * of the other AddWatchOnly which accepts a timestamp and sets
407 * nTimeFirstKey more intelligently for more efficient rescans.
408 */
409 bool AddWatchOnly(const CScript& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
410 bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
411 //! Adds a watch-only address to the store, and saves it to disk.
412 bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest, int64_t create_time) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
413 414 //! Adds a key to the store, and saves it to disk.
415 bool AddKeyPubKeyWithDB(WalletBatch &batch,const CKey& key, const CPubKey &pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
416 417 void AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const bool internal, WalletBatch& batch);
418 419 //! Adds a script to the store and saves it to disk
420 bool AddCScriptWithDB(WalletBatch& batch, const CScript& script);
421 422 /** Add a KeyOriginInfo to the wallet */
423 bool AddKeyOriginWithDB(WalletBatch& batch, const CPubKey& pubkey, const KeyOriginInfo& info);
424 425 /* HD derive new child key (on internal or external chain) */
426 void DeriveNewChildKey(WalletBatch& batch, CKeyMetadata& metadata, CKey& secret, CHDChain& hd_chain, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
427 428 // Tracks keypool indexes to CKeyIDs of keys that have been taken out of the keypool but may be returned to it
429 std::map<int64_t, CKeyID> m_index_to_reserved_key;
430 431 //! Fetches a key from the keypool
432 bool GetKeyFromPool(CPubKey &key, const OutputType type);
433 434 /**
435 * Reserves a key from the keypool and sets nIndex to its index
436 *
437 * @param[out] nIndex the index of the key in keypool
438 * @param[out] keypool the keypool the key was drawn from, which could be the
439 * the pre-split pool if present, or the internal or external pool
440 * @param fRequestedInternal true if the caller would like the key drawn
441 * from the internal keypool, false if external is preferred
442 *
443 * @return true if succeeded, false if failed due to empty keypool
444 * @throws std::runtime_error if keypool read failed, key was invalid,
445 * was not found in the wallet, or was misclassified in the internal
446 * or external keypool
447 */
448 bool ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal);
449 450 /**
451 * Like TopUp() but adds keys for inactive HD chains.
452 * Ensures that there are at least -keypool number of keys derived after the given index.
453 *
454 * @param seed_id the CKeyID for the HD seed.
455 * @param index the index to start generating keys from
456 * @param internal whether the internal chain should be used. true for internal chain, false for external chain.
457 *
458 * @return true if seed was found and keys were derived. false if unable to derive seeds
459 */
460 bool TopUpInactiveHDChain(const CKeyID seed_id, int64_t index, bool internal);
461 462 bool TopUpChain(WalletBatch& batch, CHDChain& chain, unsigned int size);
463 public:
464 LegacyScriptPubKeyMan(WalletStorage& storage, int64_t keypool_size) : LegacyDataSPKM(storage), m_keypool_size(keypool_size) {}
465 466 util::Result<CTxDestination> GetNewDestination(const OutputType type) override;
467 468 bool Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch) override;
469 470 util::Result<CTxDestination> GetReservedDestination(const OutputType type, bool internal, int64_t& index, CKeyPool& keypool) override;
471 void KeepDestination(int64_t index, const OutputType& type) override;
472 void ReturnDestination(int64_t index, bool internal, const CTxDestination&) override;
473 474 bool TopUp(unsigned int size = 0) override;
475 476 std::vector<WalletDestination> MarkUnusedAddresses(const CScript& script) override;
477 478 //! Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo
479 void UpgradeKeyMetadata();
480 481 bool IsHDEnabled() const override;
482 483 bool SetupGeneration(bool force = false) override;
484 485 bool Upgrade(int prev_version, int new_version, bilingual_str& error) override;
486 487 bool HavePrivateKeys() const override;
488 bool HaveCryptedKeys() const override;
489 490 void RewriteDB() override;
491 492 std::optional<int64_t> GetOldestKeyPoolTime() const override;
493 size_t KeypoolCountExternalKeys() const;
494 unsigned int GetKeyPoolSize() const override;
495 496 int64_t GetTimeFirstKey() const override;
497 498 std::unique_ptr<CKeyMetadata> GetMetadata(const CTxDestination& dest) const override;
499 500 bool CanGetAddresses(bool internal = false) const override;
501 502 bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors, std::optional<CAmount>* inputs_amount_sum = nullptr) const override;
503 SigningResult SignMessage(const MessageSignatureFormat format, const std::string& message, const CTxDestination& address, std::string& str_sig) const override;
504 std::optional<common::PSBTError> FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = SIGHASH_DEFAULT, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const override;
505 506 uint256 GetID() const override;
507 508 //! Adds a key to the store, and saves it to disk.
509 bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override;
510 //! Adds an encrypted key to the store, and saves it to disk.
511 bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
512 void UpdateTimeFirstKey(int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
513 //! Load metadata (used by LoadWallet)
514 void LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &metadata) override;
515 void LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &metadata) override;
516 //! Generate a new key
517 CPubKey GenerateNewKey(WalletBatch& batch, CHDChain& hd_chain, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
518 519 /* Set the HD chain model (chain child index counters) and writes it to the database */
520 void AddHDChain(const CHDChain& chain);
521 522 //! Remove a watch only script from the keystore
523 bool RemoveWatchOnly(const CScript &dest);
524 bool AddWatchOnly(const CScript& dest, int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
525 526 /* SigningProvider overrides */
527 bool AddCScript(const CScript& redeemScript) override;
528 529 bool NewKeyPool();
530 void MarkPreSplitKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
531 532 bool ImportScripts(const std::set<CScript> scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
533 bool ImportPrivKeys(const std::map<CKeyID, CKey>& privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
534 bool ImportPubKeys(const std::vector<std::pair<CKeyID, bool>>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
535 bool ImportScriptPubKeys(const std::set<CScript>& script_pub_keys, const bool have_solving_data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
536 537 /* Returns true if the wallet can generate new keys */
538 bool CanGenerateKeys() const;
539 540 /* Generates a new HD seed (will not be activated) */
541 CPubKey GenerateNewSeed();
542 543 /* Derives a new HD seed (will not be activated) */
544 CPubKey DeriveNewSeed(const CKey& key);
545 546 /* Set the current HD seed (will reset the chain child index counters)
547 Sets the seed's version based on the current wallet version (so the
548 caller must ensure the current wallet version is correct before calling
549 this function). */
550 void SetHDSeed(const CPubKey& key);
551 552 /**
553 * Explicitly make the wallet learn the related scripts for outputs to the
554 * given key. This is purely to make the wallet file compatible with older
555 * software, as FillableSigningProvider automatically does this implicitly for all
556 * keys now.
557 */
558 void LearnRelatedScripts(const CPubKey& key, OutputType);
559 560 /**
561 * Same as LearnRelatedScripts, but when the OutputType is not known (and could
562 * be anything).
563 */
564 void LearnAllRelatedScripts(const CPubKey& key);
565 566 /**
567 * Marks all keys in the keypool up to and including the provided key as used.
568 *
569 * @param keypool_id determines the last key to mark as used
570 *
571 * @return All affected keys
572 */
573 std::vector<CKeyPool> MarkReserveKeysAsUsed(int64_t keypool_id) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
574 const std::map<CKeyID, int64_t>& GetAllReserveKeys() const { return m_pool_key_to_index; }
575 576 std::set<CKeyID> GetKeys() const override;
577 };
578 579 /** Wraps a LegacyScriptPubKeyMan so that it can be returned in a new unique_ptr. Does not provide privkeys */
580 class LegacySigningProvider : public SigningProvider
581 {
582 private:
583 const LegacyDataSPKM& m_spk_man;
584 public:
585 explicit LegacySigningProvider(const LegacyDataSPKM& spk_man) : m_spk_man(spk_man) {}
586 587 bool GetCScript(const CScriptID &scriptid, CScript& script) const override { return m_spk_man.GetCScript(scriptid, script); }
588 bool HaveCScript(const CScriptID &scriptid) const override { return m_spk_man.HaveCScript(scriptid); }
589 bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const override { return m_spk_man.GetPubKey(address, pubkey); }
590 bool GetKey(const CKeyID &address, CKey& key) const override { return false; }
591 bool HaveKey(const CKeyID &address) const override { return false; }
592 bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override { return m_spk_man.GetKeyOrigin(keyid, info); }
593 };
594 595 class DescriptorScriptPubKeyMan : public ScriptPubKeyMan
596 {
597 friend class LegacyDataSPKM;
598 private:
599 using ScriptPubKeyMap = std::map<CScript, int32_t>; // Map of scripts to descriptor range index
600 using PubKeyMap = std::map<CPubKey, int32_t>; // Map of pubkeys involved in scripts to descriptor range index
601 using CryptedKeyMap = std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char>>>;
602 using KeyMap = std::map<CKeyID, CKey>;
603 604 ScriptPubKeyMap m_map_script_pub_keys GUARDED_BY(cs_desc_man);
605 PubKeyMap m_map_pubkeys GUARDED_BY(cs_desc_man);
606 int32_t m_max_cached_index = -1;
607 608 KeyMap m_map_keys GUARDED_BY(cs_desc_man);
609 CryptedKeyMap m_map_crypted_keys GUARDED_BY(cs_desc_man);
610 611 //! keeps track of whether Unlock has run a thorough check before
612 bool m_decryption_thoroughly_checked = false;
613 614 //! Number of pre-generated keys/scripts (part of the look-ahead process, used to detect payments)
615 int64_t m_keypool_size GUARDED_BY(cs_desc_man){DEFAULT_KEYPOOL_SIZE};
616 617 bool AddDescriptorKeyWithDB(WalletBatch& batch, const CKey& key, const CPubKey &pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
618 619 KeyMap GetKeys() const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
620 621 // Cached FlatSigningProviders to avoid regenerating them each time they are needed.
622 mutable std::map<int32_t, FlatSigningProvider> m_map_signing_providers;
623 // Fetch the SigningProvider for the given script and optionally include private keys
624 std::unique_ptr<FlatSigningProvider> GetSigningProvider(const CScript& script, bool include_private = false) const;
625 // Fetch the SigningProvider for a given index and optionally include private keys. Called by the above functions.
626 std::unique_ptr<FlatSigningProvider> GetSigningProvider(int32_t index, bool include_private = false) const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
627 628 protected:
629 WalletDescriptor m_wallet_descriptor GUARDED_BY(cs_desc_man);
630 631 //! Same as 'TopUp' but designed for use within a batch transaction context
632 bool TopUpWithDB(WalletBatch& batch, unsigned int size = 0);
633 634 public:
635 DescriptorScriptPubKeyMan(WalletStorage& storage, WalletDescriptor& descriptor, int64_t keypool_size)
636 : ScriptPubKeyMan(storage),
637 m_keypool_size(keypool_size),
638 m_wallet_descriptor(descriptor)
639 {}
640 DescriptorScriptPubKeyMan(WalletStorage& storage, int64_t keypool_size)
641 : ScriptPubKeyMan(storage),
642 m_keypool_size(keypool_size)
643 {}
644 645 mutable RecursiveMutex cs_desc_man;
646 647 util::Result<CTxDestination> GetNewDestination(const OutputType type) override;
648 isminetype IsMine(const CScript& script) const override;
649 650 bool CheckDecryptionKey(const CKeyingMaterial& master_key) override;
651 bool Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch) override;
652 653 util::Result<CTxDestination> GetReservedDestination(const OutputType type, bool internal, int64_t& index, CKeyPool& keypool) override;
654 void ReturnDestination(int64_t index, bool internal, const CTxDestination& addr) override;
655 656 // Tops up the descriptor cache and m_map_script_pub_keys. The cache is stored in the wallet file
657 // and is used to expand the descriptor in GetNewDestination. DescriptorScriptPubKeyMan relies
658 // more on ephemeral data than LegacyScriptPubKeyMan. For wallets using unhardened derivation
659 // (with or without private keys), the "keypool" is a single xpub.
660 bool TopUp(unsigned int size = 0) override;
661 662 std::vector<WalletDestination> MarkUnusedAddresses(const CScript& script) override;
663 664 [[nodiscard]] bool IsKeyActive(const CScript& script) const override { return IsMine(script); }
665 666 bool IsHDEnabled() const override;
667 668 //! Setup descriptors based on the given CExtkey
669 bool SetupDescriptorGeneration(WalletBatch& batch, const CExtKey& master_key, OutputType addr_type, bool internal);
670 671 bool HavePrivateKeys() const override;
672 bool HasPrivKey(const CKeyID& keyid) const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
673 //! Retrieve the particular key if it is available. Returns nullopt if the key is not in the wallet, or if the wallet is locked.
674 std::optional<CKey> GetKey(const CKeyID& keyid) const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
675 bool HaveCryptedKeys() const override;
676 677 std::optional<int64_t> GetOldestKeyPoolTime() const override;
678 unsigned int GetKeyPoolSize() const override;
679 680 int64_t GetTimeFirstKey() const override;
681 682 std::unique_ptr<CKeyMetadata> GetMetadata(const CTxDestination& dest) const override;
683 684 bool CanGetAddresses(bool internal = false) const override;
685 686 std::unique_ptr<SigningProvider> GetSolvingProvider(const CScript& script) const override;
687 688 bool CanProvide(const CScript& script, SignatureData& sigdata) override;
689 690 // Fetch the SigningProvider for the given pubkey and always include private keys. This should only be called by signing code.
691 std::unique_ptr<FlatSigningProvider> GetSigningProvider(const CPubKey& pubkey) const;
692 693 bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors, std::optional<CAmount>* inputs_amount_sum = nullptr) const override;
694 SigningResult SignMessage(const MessageSignatureFormat format, const std::string& message, const CTxDestination& address, std::string& str_sig) const override;
695 std::optional<common::PSBTError> FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = SIGHASH_DEFAULT, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const override;
696 697 uint256 GetID() const override;
698 699 void SetCache(const DescriptorCache& cache);
700 701 bool AddKey(const CKeyID& key_id, const CKey& key);
702 bool AddCryptedKey(const CKeyID& key_id, const CPubKey& pubkey, const std::vector<unsigned char>& crypted_key);
703 704 bool HasWalletDescriptor(const WalletDescriptor& desc) const;
705 void UpdateWalletDescriptor(WalletDescriptor& descriptor);
706 bool CanUpdateToWalletDescriptor(const WalletDescriptor& descriptor, std::string& error);
707 void AddDescriptorKey(const CKey& key, const CPubKey &pubkey);
708 void WriteDescriptor();
709 710 WalletDescriptor GetWalletDescriptor() const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
711 std::unordered_set<CScript, SaltedSipHasher> GetScriptPubKeys() const override;
712 std::unordered_set<CScript, SaltedSipHasher> GetScriptPubKeys(int32_t minimum_index) const;
713 int32_t GetEndRange() const;
714 715 [[nodiscard]] bool GetDescriptorString(std::string& out, const bool priv) const;
716 717 void UpgradeDescriptorCache();
718 };
719 720 /** struct containing information needed for migrating legacy wallets to descriptor wallets */
721 struct MigrationData
722 {
723 CExtKey master_key;
724 std::vector<std::pair<std::string, int64_t>> watch_descs;
725 std::vector<std::pair<std::string, int64_t>> solvable_descs;
726 std::vector<std::unique_ptr<DescriptorScriptPubKeyMan>> desc_spkms;
727 std::shared_ptr<CWallet> watchonly_wallet{nullptr};
728 std::shared_ptr<CWallet> solvable_wallet{nullptr};
729 };
730 731 } // namespace wallet
732 733 #endif // LIMENKA_WALLET_SCRIPTPUBKEYMAN_H
734