Merge #16227: Refactor CWallet's inheritance chain

93ce4a0b6f Move WatchOnly stuff from SigningProvider to CWallet (Andrew Chow)
8f5b81e6ed Remove CCryptoKeyStore and move all of it's functionality into CWallet (Andrew Chow)
37a79a4fcc Move various SigningProviders to signingprovider.{cpp,h} (Andrew Chow)
16f8096e91 Move KeyOriginInfo to its own header file (Andrew Chow)
d9becff4e1 scripted-diff: rename CBasicKeyStore to FillableSigningProvider (Andrew Chow)
a913e3f2fb Move HaveKey static function from keystore to rpcwallet where it is used (Andrew Chow)
c7797ec655 Remove CKeyStore and squash into CBasicKeyStore (Andrew Chow)
1b699a5083 Add HaveKey and HaveCScript to SigningProvider (Andrew Chow)

Pull request description:

  This PR compresses the `CWallet` chain of inheritance from 5 classes to 3 classes. `CBasicKeyStore` is renamed to `FillableSigningProvider` and some parts of it (the watchonly parts) are moved into `CWallet`. `CKeyStore` and `CCrypoKeyStore` are completely removed. `CKeyStore`'s `Have*` functions are moved into `SigningProvider` and the `Add*` moved into `FillableSigningProvider`, thus allowing it to go away entirely. `CCryptoKeyStore`'s functionality is moved into `CWallet`. The new inheritance chain is:

  ```
  SigningProvider -> FillableSigningProvider -> CWallet
  ```

  `SigningProvider` now is the class the provides keys and scripts and indicates whether keys and scripts are present. `FillableSigningProvider` allows keys and scripts to be added to the signing provider via `Add*` functions. `CWallet` handles all of the watchonly stuff (`AddWatchOnly`, `HaveWatchOnly`, `RemoveWatchOnly` which were previously in `CKeyStore`) and key encryption (previously in `CCryptoKeyStore`).

  Implements the 2nd [prerequisite](https://github.com/bitcoin-core/bitcoin-devwiki/wiki/Wallet-Class-Structure-Changes#cwallet-subclass-stack) from the wallet restructure.

ACKs for top commit:
  Sjors:
    re-ACK 93ce4a0; it keeps `EncryptSecret`, `DecryptSecret` and `DecryptKey` in `wallet/crypter.cpp`, but makes them not static. It improves alphabetical includes, reorders some function definitions, fixes commit message, brings back lost code comment.
  instagibbs:
    utACK 93ce4a0b6f

Tree-SHA512: 393dfd0623ad2dac38395eb89b862424318d6072f0b7083c92a0d207fd032c48b284f5f2cb13bc492f34557de350c5fee925da02e47daf011c5c6930a721b6d3
This commit is contained in:
Wladimir J. van der Laan 2019-07-11 22:01:12 +02:00
commit 735d6b57e7
No known key found for this signature in database
GPG key ID: 1E4AED62986CD25D
36 changed files with 599 additions and 602 deletions

View file

@ -375,7 +375,7 @@ reported in the debug.log file.
Re-architecting the core code so there are better-defined interfaces Re-architecting the core code so there are better-defined interfaces
between the various components is a goal, with any necessary locking between the various components is a goal, with any necessary locking
done by the components (e.g. see the self-contained `CBasicKeyStore` class done by the components (e.g. see the self-contained `FillableSigningProvider` class
and its `cs_KeyStore` lock for example). and its `cs_KeyStore` lock for example).
Threads Threads

View file

@ -143,7 +143,6 @@ BITCOIN_CORE_H = \
interfaces/wallet.h \ interfaces/wallet.h \
key.h \ key.h \
key_io.h \ key_io.h \
keystore.h \
dbwrapper.h \ dbwrapper.h \
limitedmap.h \ limitedmap.h \
logging.h \ logging.h \
@ -182,8 +181,10 @@ BITCOIN_CORE_H = \
rpc/util.h \ rpc/util.h \
scheduler.h \ scheduler.h \
script/descriptor.h \ script/descriptor.h \
script/keyorigin.h \
script/sigcache.h \ script/sigcache.h \
script/sign.h \ script/sign.h \
script/signingprovider.h \
script/standard.h \ script/standard.h \
shutdown.h \ shutdown.h \
streams.h \ streams.h \
@ -449,7 +450,6 @@ libbitcoin_common_a_SOURCES = \
core_write.cpp \ core_write.cpp \
key.cpp \ key.cpp \
key_io.cpp \ key_io.cpp \
keystore.cpp \
merkleblock.cpp \ merkleblock.cpp \
netaddress.cpp \ netaddress.cpp \
netbase.cpp \ netbase.cpp \
@ -463,6 +463,7 @@ libbitcoin_common_a_SOURCES = \
scheduler.cpp \ scheduler.cpp \
script/descriptor.cpp \ script/descriptor.cpp \
script/sign.cpp \ script/sign.cpp \
script/signingprovider.cpp \
script/standard.cpp \ script/standard.cpp \
versionbitsinfo.cpp \ versionbitsinfo.cpp \
warnings.cpp \ warnings.cpp \

View file

@ -5,7 +5,7 @@
#include <bench/bench.h> #include <bench/bench.h>
#include <coins.h> #include <coins.h>
#include <policy/policy.h> #include <policy/policy.h>
#include <wallet/crypter.h> #include <script/signingprovider.h>
#include <vector> #include <vector>
@ -17,7 +17,7 @@
// paid to a TX_PUBKEYHASH. // paid to a TX_PUBKEYHASH.
// //
static std::vector<CMutableTransaction> static std::vector<CMutableTransaction>
SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet) SetupDummyInputs(FillableSigningProvider& keystoreRet, CCoinsViewCache& coinsRet)
{ {
std::vector<CMutableTransaction> dummyTransactions; std::vector<CMutableTransaction> dummyTransactions;
dummyTransactions.resize(2); dummyTransactions.resize(2);
@ -55,7 +55,7 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
// (https://github.com/bitcoin/bitcoin/issues/7883#issuecomment-224807484) // (https://github.com/bitcoin/bitcoin/issues/7883#issuecomment-224807484)
static void CCoinsCaching(benchmark::State& state) static void CCoinsCaching(benchmark::State& state)
{ {
CBasicKeyStore keystore; FillableSigningProvider keystore;
CCoinsView coinsDummy; CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy); CCoinsViewCache coins(&coinsDummy);
std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins); std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);

View file

@ -11,12 +11,12 @@
#include <consensus/consensus.h> #include <consensus/consensus.h>
#include <core_io.h> #include <core_io.h>
#include <key_io.h> #include <key_io.h>
#include <keystore.h>
#include <policy/policy.h> #include <policy/policy.h>
#include <policy/rbf.h> #include <policy/rbf.h>
#include <primitives/transaction.h> #include <primitives/transaction.h>
#include <script/script.h> #include <script/script.h>
#include <script/sign.h> #include <script/sign.h>
#include <script/signingprovider.h>
#include <univalue.h> #include <univalue.h>
#include <util/rbf.h> #include <util/rbf.h>
#include <util/system.h> #include <util/system.h>
@ -557,7 +557,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
if (!registers.count("privatekeys")) if (!registers.count("privatekeys"))
throw std::runtime_error("privatekeys register variable must be set."); throw std::runtime_error("privatekeys register variable must be set.");
CBasicKeyStore tempKeystore; FillableSigningProvider tempKeystore;
UniValue keysObj = registers["privatekeys"]; UniValue keysObj = registers["privatekeys"];
for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) { for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) {
@ -631,7 +631,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
} }
} }
const CKeyStore& keystore = tempKeystore; const FillableSigningProvider& keystore = tempKeystore;
bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE); bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);

View file

@ -478,7 +478,7 @@ public:
} }
std::unique_ptr<Handler> handleStatusChanged(StatusChangedFn fn) override std::unique_ptr<Handler> handleStatusChanged(StatusChangedFn fn) override
{ {
return MakeHandler(m_wallet->NotifyStatusChanged.connect([fn](CCryptoKeyStore*) { fn(); })); return MakeHandler(m_wallet->NotifyStatusChanged.connect([fn](CWallet*) { fn(); }));
} }
std::unique_ptr<Handler> handleAddressBookChanged(AddressBookChangedFn fn) override std::unique_ptr<Handler> handleAddressBookChanged(AddressBookChangedFn fn) override
{ {

View file

@ -1,83 +0,0 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_KEYSTORE_H
#define BITCOIN_KEYSTORE_H
#include <key.h>
#include <pubkey.h>
#include <script/script.h>
#include <script/sign.h>
#include <script/standard.h>
#include <sync.h>
#include <boost/signals2/signal.hpp>
/** A virtual base class for key stores */
class CKeyStore : public SigningProvider
{
public:
//! Add a key to the store.
virtual bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) =0;
//! Check whether a key corresponding to a given address is present in the store.
virtual bool HaveKey(const CKeyID &address) const =0;
virtual std::set<CKeyID> GetKeys() const =0;
//! Support for BIP 0013 : see https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki
virtual bool AddCScript(const CScript& redeemScript) =0;
virtual bool HaveCScript(const CScriptID &hash) const =0;
virtual std::set<CScriptID> GetCScripts() const =0;
//! Support for Watch-only addresses
virtual bool AddWatchOnly(const CScript &dest) =0;
virtual bool RemoveWatchOnly(const CScript &dest) =0;
virtual bool HaveWatchOnly(const CScript &dest) const =0;
virtual bool HaveWatchOnly() const =0;
};
/** Basic key store, that keeps keys in an address->secret map */
class CBasicKeyStore : public CKeyStore
{
protected:
mutable CCriticalSection cs_KeyStore;
using KeyMap = std::map<CKeyID, CKey>;
using WatchKeyMap = std::map<CKeyID, CPubKey>;
using ScriptMap = std::map<CScriptID, CScript>;
using WatchOnlySet = std::set<CScript>;
KeyMap mapKeys GUARDED_BY(cs_KeyStore);
WatchKeyMap mapWatchKeys GUARDED_BY(cs_KeyStore);
ScriptMap mapScripts GUARDED_BY(cs_KeyStore);
WatchOnlySet setWatchOnly GUARDED_BY(cs_KeyStore);
void ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
public:
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override;
bool AddKey(const CKey &key) { return AddKeyPubKey(key, key.GetPubKey()); }
bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
bool HaveKey(const CKeyID &address) const override;
std::set<CKeyID> GetKeys() const override;
bool GetKey(const CKeyID &address, CKey &keyOut) const override;
bool AddCScript(const CScript& redeemScript) override;
bool HaveCScript(const CScriptID &hash) const override;
std::set<CScriptID> GetCScripts() const override;
bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const override;
bool AddWatchOnly(const CScript &dest) override;
bool RemoveWatchOnly(const CScript &dest) override;
bool HaveWatchOnly(const CScript &dest) const override;
bool HaveWatchOnly() const override;
};
/** Return the CKeyID of the key involved in a script (if there is a unique one). */
CKeyID GetKeyForDestination(const CKeyStore& store, const CTxDestination& dest);
/** Checks if a CKey is in the given CKeyStore compressed or otherwise*/
bool HaveKey(const CKeyStore& store, const CKey& key);
#endif // BITCOIN_KEYSTORE_H

View file

@ -5,9 +5,10 @@
#include <outputtype.h> #include <outputtype.h>
#include <keystore.h>
#include <pubkey.h> #include <pubkey.h>
#include <script/script.h> #include <script/script.h>
#include <script/sign.h>
#include <script/signingprovider.h>
#include <script/standard.h> #include <script/standard.h>
#include <assert.h> #include <assert.h>
@ -73,7 +74,7 @@ std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key)
} }
} }
CTxDestination AddAndGetDestinationForScript(CKeyStore& keystore, const CScript& script, OutputType type) CTxDestination AddAndGetDestinationForScript(FillableSigningProvider& keystore, const CScript& script, OutputType type)
{ {
// Add script to keystore // Add script to keystore
keystore.AddCScript(script); keystore.AddCScript(script);
@ -98,4 +99,3 @@ CTxDestination AddAndGetDestinationForScript(CKeyStore& keystore, const CScript&
default: assert(false); default: assert(false);
} }
} }

View file

@ -7,7 +7,7 @@
#define BITCOIN_OUTPUTTYPE_H #define BITCOIN_OUTPUTTYPE_H
#include <attributes.h> #include <attributes.h>
#include <keystore.h> #include <script/signingprovider.h>
#include <script/standard.h> #include <script/standard.h>
#include <string> #include <string>
@ -44,7 +44,7 @@ std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key);
* This function will automatically add the script (and any other * This function will automatically add the script (and any other
* necessary scripts) to the keystore. * necessary scripts) to the keystore.
*/ */
CTxDestination AddAndGetDestinationForScript(CKeyStore& keystore, const CScript& script, OutputType); CTxDestination AddAndGetDestinationForScript(FillableSigningProvider& keystore, const CScript& script, OutputType);
#endif // BITCOIN_OUTPUTTYPE_H #endif // BITCOIN_OUTPUTTYPE_H

View file

@ -12,6 +12,7 @@
#include <primitives/transaction.h> #include <primitives/transaction.h>
#include <pubkey.h> #include <pubkey.h>
#include <script/sign.h> #include <script/sign.h>
#include <script/signingprovider.h>
// Magic bytes // Magic bytes
static constexpr uint8_t PSBT_MAGIC_BYTES[5] = {'p', 's', 'b', 't', 0xff}; static constexpr uint8_t PSBT_MAGIC_BYTES[5] = {'p', 's', 'b', 't', 0xff};

View file

@ -115,7 +115,7 @@ static UniValue createmultisig(const JSONRPCRequest& request)
} }
// Construct using pay-to-script-hash: // Construct using pay-to-script-hash:
CBasicKeyStore keystore; FillableSigningProvider keystore;
CScript inner; CScript inner;
const CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, keystore, inner); const CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, keystore, inner);

View file

@ -10,7 +10,6 @@
#include <core_io.h> #include <core_io.h>
#include <index/txindex.h> #include <index/txindex.h>
#include <key_io.h> #include <key_io.h>
#include <keystore.h>
#include <merkleblock.h> #include <merkleblock.h>
#include <node/coin.h> #include <node/coin.h>
#include <node/psbt.h> #include <node/psbt.h>
@ -24,6 +23,7 @@
#include <script/script.h> #include <script/script.h>
#include <script/script_error.h> #include <script/script_error.h>
#include <script/sign.h> #include <script/sign.h>
#include <script/signingprovider.h>
#include <script/standard.h> #include <script/standard.h>
#include <uint256.h> #include <uint256.h>
#include <util/moneystr.h> #include <util/moneystr.h>
@ -736,7 +736,7 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
} }
CBasicKeyStore keystore; FillableSigningProvider keystore;
const UniValue& keys = request.params[1].get_array(); const UniValue& keys = request.params[1].get_array();
for (unsigned int idx = 0; idx < keys.size(); ++idx) { for (unsigned int idx = 0; idx < keys.size(); ++idx) {
UniValue k = keys[idx]; UniValue k = keys[idx];

View file

@ -8,11 +8,12 @@
#include <coins.h> #include <coins.h>
#include <core_io.h> #include <core_io.h>
#include <key_io.h> #include <key_io.h>
#include <keystore.h>
#include <policy/policy.h> #include <policy/policy.h>
#include <primitives/transaction.h> #include <primitives/transaction.h>
#include <rpc/request.h> #include <rpc/request.h>
#include <rpc/util.h> #include <rpc/util.h>
#include <script/sign.h>
#include <script/signingprovider.h>
#include <tinyformat.h> #include <tinyformat.h>
#include <univalue.h> #include <univalue.h>
#include <util/rbf.h> #include <util/rbf.h>
@ -148,7 +149,7 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::
vErrorsRet.push_back(entry); vErrorsRet.push_back(entry);
} }
UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxsUnival, CBasicKeyStore* keystore, std::map<COutPoint, Coin>& coins, bool is_temp_keystore, const UniValue& hashType) UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxsUnival, FillableSigningProvider* keystore, std::map<COutPoint, Coin>& coins, bool is_temp_keystore, const UniValue& hashType)
{ {
// Add previous txouts given in the RPC call: // Add previous txouts given in the RPC call:
if (!prevTxsUnival.isNull()) { if (!prevTxsUnival.isNull()) {

View file

@ -7,7 +7,7 @@
#include <map> #include <map>
class CBasicKeyStore; class FillableSigningProvider;
class UniValue; class UniValue;
struct CMutableTransaction; struct CMutableTransaction;
class Coin; class Coin;
@ -24,7 +24,7 @@ class COutPoint;
* @param hashType The signature hash type * @param hashType The signature hash type
* @returns JSON object with details of signed transaction * @returns JSON object with details of signed transaction
*/ */
UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxs, CBasicKeyStore* keystore, std::map<COutPoint, Coin>& coins, bool tempKeystore, const UniValue& hashType); UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxs, FillableSigningProvider* keystore, std::map<COutPoint, Coin>& coins, bool tempKeystore, const UniValue& hashType);
/** Create a transaction from univalue parameters */ /** Create a transaction from univalue parameters */
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf); CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf);

View file

@ -3,8 +3,8 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <key_io.h> #include <key_io.h>
#include <keystore.h>
#include <outputtype.h> #include <outputtype.h>
#include <script/signingprovider.h>
#include <rpc/util.h> #include <rpc/util.h>
#include <script/descriptor.h> #include <script/descriptor.h>
#include <tinyformat.h> #include <tinyformat.h>
@ -131,8 +131,8 @@ CPubKey HexToPubKey(const std::string& hex_in)
return vchPubKey; return vchPubKey;
} }
// Retrieves a public key for an address from the given CKeyStore // Retrieves a public key for an address from the given FillableSigningProvider
CPubKey AddrToPubKey(CKeyStore* const keystore, const std::string& addr_in) CPubKey AddrToPubKey(FillableSigningProvider* const keystore, const std::string& addr_in)
{ {
CTxDestination dest = DecodeDestination(addr_in); CTxDestination dest = DecodeDestination(addr_in);
if (!IsValidDestination(dest)) { if (!IsValidDestination(dest)) {
@ -153,7 +153,7 @@ CPubKey AddrToPubKey(CKeyStore* const keystore, const std::string& addr_in)
} }
// Creates a multisig address from a given list of public keys, number of signatures required, and the address type // Creates a multisig address from a given list of public keys, number of signatures required, and the address type
CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, CKeyStore& keystore, CScript& script_out) CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, FillableSigningProvider& keystore, CScript& script_out)
{ {
// Gather public keys // Gather public keys
if (required < 1) { if (required < 1) {

View file

@ -20,7 +20,7 @@
#include <boost/variant.hpp> #include <boost/variant.hpp>
class CKeyStore; class FillableSigningProvider;
class CPubKey; class CPubKey;
class CScript; class CScript;
struct InitInterfaces; struct InitInterfaces;
@ -73,8 +73,8 @@ extern std::string HelpExampleCli(const std::string& methodname, const std::stri
extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args); extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args);
CPubKey HexToPubKey(const std::string& hex_in); CPubKey HexToPubKey(const std::string& hex_in);
CPubKey AddrToPubKey(CKeyStore* const keystore, const std::string& addr_in); CPubKey AddrToPubKey(FillableSigningProvider* const keystore, const std::string& addr_in);
CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, CKeyStore& keystore, CScript& script_out); CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, FillableSigningProvider& keystore, CScript& script_out);
UniValue DescribeAddress(const CTxDestination& dest); UniValue DescribeAddress(const CTxDestination& dest);

View file

@ -7,6 +7,7 @@
#include <script/script.h> #include <script/script.h>
#include <script/sign.h> #include <script/sign.h>
#include <script/signingprovider.h>
#include <vector> #include <vector>

37
src/script/keyorigin.h Normal file
View file

@ -0,0 +1,37 @@
// Copyright (c) 2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_SCRIPT_KEYORIGIN_H
#define BITCOIN_SCRIPT_KEYORIGIN_H
#include <serialize.h>
#include <streams.h>
#include <vector>
struct KeyOriginInfo
{
unsigned char fingerprint[4]; //!< First 32 bits of the Hash160 of the public key at the root of the path
std::vector<uint32_t> path;
friend bool operator==(const KeyOriginInfo& a, const KeyOriginInfo& b)
{
return std::equal(std::begin(a.fingerprint), std::end(a.fingerprint), std::begin(b.fingerprint)) && a.path == b.path;
}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(fingerprint);
READWRITE(path);
}
void clear()
{
memset(fingerprint, 0, 4);
path.clear();
}
};
#endif // BITCOIN_SCRIPT_KEYORIGIN_H

View file

@ -8,6 +8,7 @@
#include <key.h> #include <key.h>
#include <policy/policy.h> #include <policy/policy.h>
#include <primitives/transaction.h> #include <primitives/transaction.h>
#include <script/signingprovider.h>
#include <script/standard.h> #include <script/standard.h>
#include <uint256.h> #include <uint256.h>
@ -423,22 +424,10 @@ public:
} }
}; };
template<typename M, typename K, typename V>
bool LookupHelper(const M& map, const K& key, V& value)
{
auto it = map.find(key);
if (it != map.end()) {
value = it->second;
return true;
}
return false;
}
} }
const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR = DummySignatureCreator(32, 32); const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR = DummySignatureCreator(32, 32);
const BaseSignatureCreator& DUMMY_MAXIMUM_SIGNATURE_CREATOR = DummySignatureCreator(33, 32); const BaseSignatureCreator& DUMMY_MAXIMUM_SIGNATURE_CREATOR = DummySignatureCreator(33, 32);
const SigningProvider& DUMMY_SIGNING_PROVIDER = SigningProvider();
bool IsSolvable(const SigningProvider& provider, const CScript& script) bool IsSolvable(const SigningProvider& provider, const CScript& script)
{ {
@ -459,53 +448,6 @@ bool IsSolvable(const SigningProvider& provider, const CScript& script)
return false; return false;
} }
bool HidingSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const
{
return m_provider->GetCScript(scriptid, script);
}
bool HidingSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const
{
return m_provider->GetPubKey(keyid, pubkey);
}
bool HidingSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const
{
if (m_hide_secret) return false;
return m_provider->GetKey(keyid, key);
}
bool HidingSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const
{
if (m_hide_origin) return false;
return m_provider->GetKeyOrigin(keyid, info);
}
bool FlatSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const { return LookupHelper(scripts, scriptid, script); }
bool FlatSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const { return LookupHelper(pubkeys, keyid, pubkey); }
bool FlatSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const
{
std::pair<CPubKey, KeyOriginInfo> out;
bool ret = LookupHelper(origins, keyid, out);
if (ret) info = std::move(out.second);
return ret;
}
bool FlatSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const { return LookupHelper(keys, keyid, key); }
FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b)
{
FlatSigningProvider ret;
ret.scripts = a.scripts;
ret.scripts.insert(b.scripts.begin(), b.scripts.end());
ret.pubkeys = a.pubkeys;
ret.pubkeys.insert(b.pubkeys.begin(), b.pubkeys.end());
ret.keys = a.keys;
ret.keys.insert(b.keys.begin(), b.keys.end());
ret.origins = a.origins;
ret.origins.insert(b.origins.begin(), b.origins.end());
return ret;
}
bool IsSegWitOutput(const SigningProvider& provider, const CScript& script) bool IsSegWitOutput(const SigningProvider& provider, const CScript& script)
{ {
std::vector<valtype> solutions; std::vector<valtype> solutions;

View file

@ -10,6 +10,7 @@
#include <hash.h> #include <hash.h>
#include <pubkey.h> #include <pubkey.h>
#include <script/interpreter.h> #include <script/interpreter.h>
#include <script/keyorigin.h>
#include <streams.h> #include <streams.h>
class CKey; class CKey;
@ -17,77 +18,10 @@ class CKeyID;
class CScript; class CScript;
class CScriptID; class CScriptID;
class CTransaction; class CTransaction;
class SigningProvider;
struct CMutableTransaction; struct CMutableTransaction;
struct KeyOriginInfo
{
unsigned char fingerprint[4]; //!< First 32 bits of the Hash160 of the public key at the root of the path
std::vector<uint32_t> path;
friend bool operator==(const KeyOriginInfo& a, const KeyOriginInfo& b)
{
return std::equal(std::begin(a.fingerprint), std::end(a.fingerprint), std::begin(b.fingerprint)) && a.path == b.path;
}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(fingerprint);
READWRITE(path);
}
void clear()
{
memset(fingerprint, 0, 4);
path.clear();
}
};
/** An interface to be implemented by keystores that support signing. */
class SigningProvider
{
public:
virtual ~SigningProvider() {}
virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const { return false; }
virtual bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const { return false; }
virtual bool GetKey(const CKeyID &address, CKey& key) const { return false; }
virtual bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const { return false; }
};
extern const SigningProvider& DUMMY_SIGNING_PROVIDER;
class HidingSigningProvider : public SigningProvider
{
private:
const bool m_hide_secret;
const bool m_hide_origin;
const SigningProvider* m_provider;
public:
HidingSigningProvider(const SigningProvider* provider, bool hide_secret, bool hide_origin) : m_hide_secret(hide_secret), m_hide_origin(hide_origin), m_provider(provider) {}
bool GetCScript(const CScriptID& scriptid, CScript& script) const override;
bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override;
bool GetKey(const CKeyID& keyid, CKey& key) const override;
bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
};
struct FlatSigningProvider final : public SigningProvider
{
std::map<CScriptID, CScript> scripts;
std::map<CKeyID, CPubKey> pubkeys;
std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> origins;
std::map<CKeyID, CKey> keys;
bool GetCScript(const CScriptID& scriptid, CScript& script) const override;
bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override;
bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
bool GetKey(const CKeyID& keyid, CKey& key) const override;
};
FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b);
/** Interface for signature creators. */ /** Interface for signature creators. */
class BaseSignatureCreator { class BaseSignatureCreator {
public: public:

View file

@ -1,18 +1,78 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2018 The Bitcoin Core developers // Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <keystore.h> #include <script/keyorigin.h>
#include <script/signingprovider.h>
#include <script/standard.h>
#include <util/system.h> #include <util/system.h>
void CBasicKeyStore::ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey) const SigningProvider& DUMMY_SIGNING_PROVIDER = SigningProvider();
template<typename M, typename K, typename V>
bool LookupHelper(const M& map, const K& key, V& value)
{
auto it = map.find(key);
if (it != map.end()) {
value = it->second;
return true;
}
return false;
}
bool HidingSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const
{
return m_provider->GetCScript(scriptid, script);
}
bool HidingSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const
{
return m_provider->GetPubKey(keyid, pubkey);
}
bool HidingSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const
{
if (m_hide_secret) return false;
return m_provider->GetKey(keyid, key);
}
bool HidingSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const
{
if (m_hide_origin) return false;
return m_provider->GetKeyOrigin(keyid, info);
}
bool FlatSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const { return LookupHelper(scripts, scriptid, script); }
bool FlatSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const { return LookupHelper(pubkeys, keyid, pubkey); }
bool FlatSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const
{
std::pair<CPubKey, KeyOriginInfo> out;
bool ret = LookupHelper(origins, keyid, out);
if (ret) info = std::move(out.second);
return ret;
}
bool FlatSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const { return LookupHelper(keys, keyid, key); }
FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b)
{
FlatSigningProvider ret;
ret.scripts = a.scripts;
ret.scripts.insert(b.scripts.begin(), b.scripts.end());
ret.pubkeys = a.pubkeys;
ret.pubkeys.insert(b.pubkeys.begin(), b.pubkeys.end());
ret.keys = a.keys;
ret.keys.insert(b.keys.begin(), b.keys.end());
ret.origins = a.origins;
ret.origins.insert(b.origins.begin(), b.origins.end());
return ret;
}
void FillableSigningProvider::ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey)
{ {
AssertLockHeld(cs_KeyStore); AssertLockHeld(cs_KeyStore);
CKeyID key_id = pubkey.GetID(); CKeyID key_id = pubkey.GetID();
// We must actually know about this key already.
assert(HaveKey(key_id) || mapWatchKeys.count(key_id));
// This adds the redeemscripts necessary to detect P2WPKH and P2SH-P2WPKH // This adds the redeemscripts necessary to detect P2WPKH and P2SH-P2WPKH
// outputs. Technically P2WPKH outputs don't have a redeemscript to be // outputs. Technically P2WPKH outputs don't have a redeemscript to be
// spent. However, our current IsMine logic requires the corresponding // spent. However, our current IsMine logic requires the corresponding
@ -32,23 +92,17 @@ void CBasicKeyStore::ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey)
} }
} }
bool CBasicKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const bool FillableSigningProvider::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
{ {
CKey key; CKey key;
if (!GetKey(address, key)) { if (!GetKey(address, key)) {
LOCK(cs_KeyStore);
WatchKeyMap::const_iterator it = mapWatchKeys.find(address);
if (it != mapWatchKeys.end()) {
vchPubKeyOut = it->second;
return true;
}
return false; return false;
} }
vchPubKeyOut = key.GetPubKey(); vchPubKeyOut = key.GetPubKey();
return true; return true;
} }
bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey) bool FillableSigningProvider::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
{ {
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
mapKeys[pubkey.GetID()] = key; mapKeys[pubkey.GetID()] = key;
@ -56,13 +110,13 @@ bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
return true; return true;
} }
bool CBasicKeyStore::HaveKey(const CKeyID &address) const bool FillableSigningProvider::HaveKey(const CKeyID &address) const
{ {
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
return mapKeys.count(address) > 0; return mapKeys.count(address) > 0;
} }
std::set<CKeyID> CBasicKeyStore::GetKeys() const std::set<CKeyID> FillableSigningProvider::GetKeys() const
{ {
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
std::set<CKeyID> set_address; std::set<CKeyID> set_address;
@ -72,7 +126,7 @@ std::set<CKeyID> CBasicKeyStore::GetKeys() const
return set_address; return set_address;
} }
bool CBasicKeyStore::GetKey(const CKeyID &address, CKey &keyOut) const bool FillableSigningProvider::GetKey(const CKeyID &address, CKey &keyOut) const
{ {
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
KeyMap::const_iterator mi = mapKeys.find(address); KeyMap::const_iterator mi = mapKeys.find(address);
@ -83,23 +137,23 @@ bool CBasicKeyStore::GetKey(const CKeyID &address, CKey &keyOut) const
return false; return false;
} }
bool CBasicKeyStore::AddCScript(const CScript& redeemScript) bool FillableSigningProvider::AddCScript(const CScript& redeemScript)
{ {
if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE) if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
return error("CBasicKeyStore::AddCScript(): redeemScripts > %i bytes are invalid", MAX_SCRIPT_ELEMENT_SIZE); return error("FillableSigningProvider::AddCScript(): redeemScripts > %i bytes are invalid", MAX_SCRIPT_ELEMENT_SIZE);
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
mapScripts[CScriptID(redeemScript)] = redeemScript; mapScripts[CScriptID(redeemScript)] = redeemScript;
return true; return true;
} }
bool CBasicKeyStore::HaveCScript(const CScriptID& hash) const bool FillableSigningProvider::HaveCScript(const CScriptID& hash) const
{ {
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
return mapScripts.count(hash) > 0; return mapScripts.count(hash) > 0;
} }
std::set<CScriptID> CBasicKeyStore::GetCScripts() const std::set<CScriptID> FillableSigningProvider::GetCScripts() const
{ {
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
std::set<CScriptID> set_script; std::set<CScriptID> set_script;
@ -109,7 +163,7 @@ std::set<CScriptID> CBasicKeyStore::GetCScripts() const
return set_script; return set_script;
} }
bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const bool FillableSigningProvider::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const
{ {
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
ScriptMap::const_iterator mi = mapScripts.find(hash); ScriptMap::const_iterator mi = mapScripts.find(hash);
@ -121,60 +175,7 @@ bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut)
return false; return false;
} }
static bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut) CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& dest)
{
//TODO: Use Solver to extract this?
CScript::const_iterator pc = dest.begin();
opcodetype opcode;
std::vector<unsigned char> vch;
if (!dest.GetOp(pc, opcode, vch) || !CPubKey::ValidSize(vch))
return false;
pubKeyOut = CPubKey(vch);
if (!pubKeyOut.IsFullyValid())
return false;
if (!dest.GetOp(pc, opcode, vch) || opcode != OP_CHECKSIG || dest.GetOp(pc, opcode, vch))
return false;
return true;
}
bool CBasicKeyStore::AddWatchOnly(const CScript &dest)
{
LOCK(cs_KeyStore);
setWatchOnly.insert(dest);
CPubKey pubKey;
if (ExtractPubKey(dest, pubKey)) {
mapWatchKeys[pubKey.GetID()] = pubKey;
ImplicitlyLearnRelatedKeyScripts(pubKey);
}
return true;
}
bool CBasicKeyStore::RemoveWatchOnly(const CScript &dest)
{
LOCK(cs_KeyStore);
setWatchOnly.erase(dest);
CPubKey pubKey;
if (ExtractPubKey(dest, pubKey)) {
mapWatchKeys.erase(pubKey.GetID());
}
// Related CScripts are not removed; having superfluous scripts around is
// harmless (see comment in ImplicitlyLearnRelatedKeyScripts).
return true;
}
bool CBasicKeyStore::HaveWatchOnly(const CScript &dest) const
{
LOCK(cs_KeyStore);
return setWatchOnly.count(dest) > 0;
}
bool CBasicKeyStore::HaveWatchOnly() const
{
LOCK(cs_KeyStore);
return (!setWatchOnly.empty());
}
CKeyID GetKeyForDestination(const CKeyStore& store, const CTxDestination& dest)
{ {
// Only supports destinations which map to single public keys, i.e. P2PKH, // Only supports destinations which map to single public keys, i.e. P2PKH,
// P2WPKH, and P2SH-P2WPKH. // P2WPKH, and P2SH-P2WPKH.
@ -196,10 +197,3 @@ CKeyID GetKeyForDestination(const CKeyStore& store, const CTxDestination& dest)
} }
return CKeyID(); return CKeyID();
} }
bool HaveKey(const CKeyStore& store, const CKey& key)
{
CKey key2;
key2.Set(key.begin(), key.end(), !key.IsCompressed());
return store.HaveKey(key.GetPubKey().GetID()) || store.HaveKey(key2.GetPubKey().GetID());
}

View file

@ -0,0 +1,92 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_SCRIPT_SIGNINGPROVIDER_H
#define BITCOIN_SCRIPT_SIGNINGPROVIDER_H
#include <key.h>
#include <pubkey.h>
#include <script/script.h>
#include <script/standard.h>
#include <sync.h>
struct KeyOriginInfo;
/** An interface to be implemented by keystores that support signing. */
class SigningProvider
{
public:
virtual ~SigningProvider() {}
virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const { return false; }
virtual bool HaveCScript(const CScriptID &scriptid) const { return false; }
virtual bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const { return false; }
virtual bool GetKey(const CKeyID &address, CKey& key) const { return false; }
virtual bool HaveKey(const CKeyID &address) const { return false; }
virtual bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const { return false; }
};
extern const SigningProvider& DUMMY_SIGNING_PROVIDER;
class HidingSigningProvider : public SigningProvider
{
private:
const bool m_hide_secret;
const bool m_hide_origin;
const SigningProvider* m_provider;
public:
HidingSigningProvider(const SigningProvider* provider, bool hide_secret, bool hide_origin) : m_hide_secret(hide_secret), m_hide_origin(hide_origin), m_provider(provider) {}
bool GetCScript(const CScriptID& scriptid, CScript& script) const override;
bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override;
bool GetKey(const CKeyID& keyid, CKey& key) const override;
bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
};
struct FlatSigningProvider final : public SigningProvider
{
std::map<CScriptID, CScript> scripts;
std::map<CKeyID, CPubKey> pubkeys;
std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> origins;
std::map<CKeyID, CKey> keys;
bool GetCScript(const CScriptID& scriptid, CScript& script) const override;
bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override;
bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
bool GetKey(const CKeyID& keyid, CKey& key) const override;
};
FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b);
/** Fillable signing provider that keeps keys in an address->secret map */
class FillableSigningProvider : public SigningProvider
{
protected:
mutable CCriticalSection cs_KeyStore;
using KeyMap = std::map<CKeyID, CKey>;
using ScriptMap = std::map<CScriptID, CScript>;
KeyMap mapKeys GUARDED_BY(cs_KeyStore);
ScriptMap mapScripts GUARDED_BY(cs_KeyStore);
void ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
public:
virtual bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
virtual bool AddKey(const CKey &key) { return AddKeyPubKey(key, key.GetPubKey()); }
virtual bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
virtual bool HaveKey(const CKeyID &address) const override;
virtual std::set<CKeyID> GetKeys() const;
virtual bool GetKey(const CKeyID &address, CKey &keyOut) const override;
virtual bool AddCScript(const CScript& redeemScript);
virtual bool HaveCScript(const CScriptID &hash) const override;
virtual std::set<CScriptID> GetCScripts() const;
virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const override;
};
/** Return the CKeyID of the key involved in a script (if there is a unique one). */
CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& dest);
#endif // BITCOIN_SCRIPT_SIGNINGPROVIDER_H

View file

@ -9,7 +9,6 @@
#include <pubkey.h> #include <pubkey.h>
#include <script/script.h> #include <script/script.h>
typedef std::vector<unsigned char> valtype; typedef std::vector<unsigned char> valtype;
bool fAcceptDatacarrier = DEFAULT_ACCEPT_DATACARRIER; bool fAcceptDatacarrier = DEFAULT_ACCEPT_DATACARRIER;

View file

@ -6,10 +6,11 @@
#include <banman.h> #include <banman.h>
#include <chainparams.h> #include <chainparams.h>
#include <keystore.h>
#include <net.h> #include <net.h>
#include <net_processing.h> #include <net_processing.h>
#include <script/sign.h> #include <script/sign.h>
#include <script/signingprovider.h>
#include <script/standard.h>
#include <serialize.h> #include <serialize.h>
#include <util/memory.h> #include <util/memory.h>
#include <util/system.h> #include <util/system.h>
@ -369,7 +370,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
{ {
CKey key; CKey key;
key.MakeNewKey(true); key.MakeNewKey(true);
CBasicKeyStore keystore; FillableSigningProvider keystore;
BOOST_CHECK(keystore.AddKey(key)); BOOST_CHECK(keystore.AddKey(key));
// 50 orphan transactions: // 50 orphan transactions:

View file

@ -3,12 +3,12 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <key.h> #include <key.h>
#include <keystore.h>
#include <policy/policy.h> #include <policy/policy.h>
#include <script/script.h> #include <script/script.h>
#include <script/script_error.h> #include <script/script_error.h>
#include <script/interpreter.h> #include <script/interpreter.h>
#include <script/sign.h> #include <script/sign.h>
#include <script/signingprovider.h>
#include <tinyformat.h> #include <tinyformat.h>
#include <uint256.h> #include <uint256.h>
#include <test/setup_common.h> #include <test/setup_common.h>
@ -174,7 +174,7 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
BOOST_AUTO_TEST_CASE(multisig_Sign) BOOST_AUTO_TEST_CASE(multisig_Sign)
{ {
// Test SignSignature() (and therefore the version of Solver() that signs transactions) // Test SignSignature() (and therefore the version of Solver() that signs transactions)
CBasicKeyStore keystore; FillableSigningProvider keystore;
CKey key[4]; CKey key[4];
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {

View file

@ -4,13 +4,13 @@
#include <consensus/tx_verify.h> #include <consensus/tx_verify.h>
#include <key.h> #include <key.h>
#include <keystore.h>
#include <validation.h> #include <validation.h>
#include <policy/policy.h> #include <policy/policy.h>
#include <script/script.h> #include <script/script.h>
#include <script/script_error.h> #include <script/script_error.h>
#include <policy/settings.h> #include <policy/settings.h>
#include <script/sign.h> #include <script/sign.h>
#include <script/signingprovider.h>
#include <test/setup_common.h> #include <test/setup_common.h>
#include <vector> #include <vector>
@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(sign)
// scriptPubKey: HASH160 <hash> EQUAL // scriptPubKey: HASH160 <hash> EQUAL
// Test SignSignature() (and therefore the version of Solver() that signs transactions) // Test SignSignature() (and therefore the version of Solver() that signs transactions)
CBasicKeyStore keystore; FillableSigningProvider keystore;
CKey key[4]; CKey key[4];
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
@ -151,7 +151,7 @@ BOOST_AUTO_TEST_CASE(set)
{ {
LOCK(cs_main); LOCK(cs_main);
// Test the CScript::Set* methods // Test the CScript::Set* methods
CBasicKeyStore keystore; FillableSigningProvider keystore;
CKey key[4]; CKey key[4];
std::vector<CPubKey> keys; std::vector<CPubKey> keys;
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
@ -265,7 +265,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
LOCK(cs_main); LOCK(cs_main);
CCoinsView coinsDummy; CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy); CCoinsViewCache coins(&coinsDummy);
CBasicKeyStore keystore; FillableSigningProvider keystore;
CKey key[6]; CKey key[6];
std::vector<CPubKey> keys; std::vector<CPubKey> keys;
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)

View file

@ -3,8 +3,8 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <key.h> #include <key.h>
#include <keystore.h>
#include <script/script.h> #include <script/script.h>
#include <script/signingprovider.h>
#include <script/standard.h> #include <script/standard.h>
#include <test/setup_common.h> #include <test/setup_common.h>

View file

@ -6,10 +6,10 @@
#include <core_io.h> #include <core_io.h>
#include <key.h> #include <key.h>
#include <keystore.h>
#include <script/script.h> #include <script/script.h>
#include <script/script_error.h> #include <script/script_error.h>
#include <script/sign.h> #include <script/sign.h>
#include <script/signingprovider.h>
#include <util/system.h> #include <util/system.h>
#include <util/strencodings.h> #include <util/strencodings.h>
#include <test/setup_common.h> #include <test/setup_common.h>
@ -1199,7 +1199,7 @@ SignatureData CombineSignatures(const CTxOut& txout, const CMutableTransaction&
BOOST_AUTO_TEST_CASE(script_combineSigs) BOOST_AUTO_TEST_CASE(script_combineSigs)
{ {
// Test the ProduceSignature's ability to combine signatures function // Test the ProduceSignature's ability to combine signatures function
CBasicKeyStore keystore; FillableSigningProvider keystore;
std::vector<CKey> keys; std::vector<CKey> keys;
std::vector<CPubKey> pubkeys; std::vector<CPubKey> pubkeys;
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)

View file

@ -12,12 +12,12 @@
#include <consensus/validation.h> #include <consensus/validation.h>
#include <core_io.h> #include <core_io.h>
#include <key.h> #include <key.h>
#include <keystore.h>
#include <validation.h> #include <validation.h>
#include <policy/policy.h> #include <policy/policy.h>
#include <policy/settings.h> #include <policy/settings.h>
#include <script/script.h> #include <script/script.h>
#include <script/sign.h> #include <script/sign.h>
#include <script/signingprovider.h>
#include <script/script_error.h> #include <script/script_error.h>
#include <script/standard.h> #include <script/standard.h>
#include <streams.h> #include <streams.h>
@ -289,7 +289,7 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
// paid to a TX_PUBKEYHASH. // paid to a TX_PUBKEYHASH.
// //
static std::vector<CMutableTransaction> static std::vector<CMutableTransaction>
SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet) SetupDummyInputs(FillableSigningProvider& keystoreRet, CCoinsViewCache& coinsRet)
{ {
std::vector<CMutableTransaction> dummyTransactions; std::vector<CMutableTransaction> dummyTransactions;
dummyTransactions.resize(2); dummyTransactions.resize(2);
@ -322,7 +322,7 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
BOOST_AUTO_TEST_CASE(test_Get) BOOST_AUTO_TEST_CASE(test_Get)
{ {
CBasicKeyStore keystore; FillableSigningProvider keystore;
CCoinsView coinsDummy; CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy); CCoinsViewCache coins(&coinsDummy);
std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins); std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
@ -346,7 +346,7 @@ BOOST_AUTO_TEST_CASE(test_Get)
BOOST_CHECK_EQUAL(coins.GetValueIn(CTransaction(t1)), (50+21+22)*CENT); BOOST_CHECK_EQUAL(coins.GetValueIn(CTransaction(t1)), (50+21+22)*CENT);
} }
static void CreateCreditAndSpend(const CKeyStore& keystore, const CScript& outscript, CTransactionRef& output, CMutableTransaction& input, bool success = true) static void CreateCreditAndSpend(const FillableSigningProvider& keystore, const CScript& outscript, CTransactionRef& output, CMutableTransaction& input, bool success = true)
{ {
CMutableTransaction outputm; CMutableTransaction outputm;
outputm.nVersion = 1; outputm.nVersion = 1;
@ -423,7 +423,7 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction)
CKey key; CKey key;
key.MakeNewKey(true); // Need to use compressed keys in segwit or the signing will fail key.MakeNewKey(true); // Need to use compressed keys in segwit or the signing will fail
CBasicKeyStore keystore; FillableSigningProvider keystore;
BOOST_CHECK(keystore.AddKeyPubKey(key, key.GetPubKey())); BOOST_CHECK(keystore.AddKeyPubKey(key, key.GetPubKey()));
CKeyID hash = key.GetPubKey().GetID(); CKeyID hash = key.GetPubKey().GetID();
CScript scriptPubKey = CScript() << OP_0 << std::vector<unsigned char>(hash.begin(), hash.end()); CScript scriptPubKey = CScript() << OP_0 << std::vector<unsigned char>(hash.begin(), hash.end());
@ -507,7 +507,7 @@ SignatureData CombineSignatures(const CMutableTransaction& input1, const CMutabl
BOOST_AUTO_TEST_CASE(test_witness) BOOST_AUTO_TEST_CASE(test_witness)
{ {
CBasicKeyStore keystore, keystore2; FillableSigningProvider keystore, keystore2;
CKey key1, key2, key3, key1L, key2L; CKey key1, key2, key3, key1L, key2L;
CPubKey pubkey1, pubkey2, pubkey3, pubkey1L, pubkey2L; CPubKey pubkey1, pubkey2, pubkey3, pubkey1L, pubkey2L;
key1.MakeNewKey(true); key1.MakeNewKey(true);
@ -682,7 +682,7 @@ BOOST_AUTO_TEST_CASE(test_witness)
BOOST_AUTO_TEST_CASE(test_IsStandard) BOOST_AUTO_TEST_CASE(test_IsStandard)
{ {
LOCK(cs_main); LOCK(cs_main);
CBasicKeyStore keystore; FillableSigningProvider keystore;
CCoinsView coinsDummy; CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy); CCoinsViewCache coins(&coinsDummy);
std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins); std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);

View file

@ -8,8 +8,8 @@
#include <txmempool.h> #include <txmempool.h>
#include <script/standard.h> #include <script/standard.h>
#include <script/sign.h> #include <script/sign.h>
#include <script/signingprovider.h>
#include <test/setup_common.h> #include <test/setup_common.h>
#include <keystore.h>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
@ -161,7 +161,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
CScript p2pkh_scriptPubKey = GetScriptForDestination(PKHash(coinbaseKey.GetPubKey())); CScript p2pkh_scriptPubKey = GetScriptForDestination(PKHash(coinbaseKey.GetPubKey()));
CScript p2wpkh_scriptPubKey = GetScriptForWitness(p2pkh_scriptPubKey); CScript p2wpkh_scriptPubKey = GetScriptForWitness(p2pkh_scriptPubKey);
CBasicKeyStore keystore; FillableSigningProvider keystore;
BOOST_CHECK(keystore.AddKey(coinbaseKey)); BOOST_CHECK(keystore.AddKey(coinbaseKey));
BOOST_CHECK(keystore.AddCScript(p2pk_scriptPubKey)); BOOST_CHECK(keystore.AddCScript(p2pk_scriptPubKey));

View file

@ -107,8 +107,7 @@ bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingM
return true; return true;
} }
bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
{ {
CCrypter cKeyCrypter; CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE); std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
@ -118,7 +117,7 @@ static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMateri
return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext); return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
} }
static bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext) bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
{ {
CCrypter cKeyCrypter; CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE); std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
@ -128,7 +127,7 @@ static bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<u
return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext)); return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
} }
static bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key) bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)
{ {
CKeyingMaterial vchSecret; CKeyingMaterial vchSecret;
if(!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret)) if(!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
@ -140,188 +139,3 @@ static bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsi
key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed()); key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
return key.VerifyPubKey(vchPubKey); return key.VerifyPubKey(vchPubKey);
} }
bool CCryptoKeyStore::SetCrypted()
{
LOCK(cs_KeyStore);
if (fUseCrypto)
return true;
if (!mapKeys.empty())
return false;
fUseCrypto = true;
return true;
}
bool CCryptoKeyStore::IsLocked() const
{
if (!IsCrypted()) {
return false;
}
LOCK(cs_KeyStore);
return vMasterKey.empty();
}
bool CCryptoKeyStore::Lock()
{
if (!SetCrypted())
return false;
{
LOCK(cs_KeyStore);
vMasterKey.clear();
}
NotifyStatusChanged(this);
return true;
}
bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys)
{
{
LOCK(cs_KeyStore);
if (!SetCrypted())
return false;
bool keyPass = mapCryptedKeys.empty(); // Always pass when there are no encrypted keys
bool keyFail = false;
CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
for (; mi != mapCryptedKeys.end(); ++mi)
{
const CPubKey &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
CKey key;
if (!DecryptKey(vMasterKeyIn, vchCryptedSecret, vchPubKey, key))
{
keyFail = true;
break;
}
keyPass = true;
if (fDecryptionThoroughlyChecked)
break;
}
if (keyPass && keyFail)
{
LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
throw std::runtime_error("Error unlocking wallet: some keys decrypt but not all. Your wallet file may be corrupt.");
}
if (keyFail || (!keyPass && !accept_no_keys))
return false;
vMasterKey = vMasterKeyIn;
fDecryptionThoroughlyChecked = true;
}
NotifyStatusChanged(this);
return true;
}
bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
{
LOCK(cs_KeyStore);
if (!IsCrypted()) {
return CBasicKeyStore::AddKeyPubKey(key, pubkey);
}
if (IsLocked()) {
return false;
}
std::vector<unsigned char> vchCryptedSecret;
CKeyingMaterial vchSecret(key.begin(), key.end());
if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret)) {
return false;
}
if (!AddCryptedKey(pubkey, vchCryptedSecret)) {
return false;
}
return true;
}
bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{
LOCK(cs_KeyStore);
if (!SetCrypted()) {
return false;
}
mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
ImplicitlyLearnRelatedKeyScripts(vchPubKey);
return true;
}
bool CCryptoKeyStore::HaveKey(const CKeyID &address) const
{
LOCK(cs_KeyStore);
if (!IsCrypted()) {
return CBasicKeyStore::HaveKey(address);
}
return mapCryptedKeys.count(address) > 0;
}
bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
{
LOCK(cs_KeyStore);
if (!IsCrypted()) {
return CBasicKeyStore::GetKey(address, keyOut);
}
CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
if (mi != mapCryptedKeys.end())
{
const CPubKey &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
}
return false;
}
bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
{
LOCK(cs_KeyStore);
if (!IsCrypted())
return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
if (mi != mapCryptedKeys.end())
{
vchPubKeyOut = (*mi).second.first;
return true;
}
// Check for watch-only pubkeys
return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
}
std::set<CKeyID> CCryptoKeyStore::GetKeys() const
{
LOCK(cs_KeyStore);
if (!IsCrypted()) {
return CBasicKeyStore::GetKeys();
}
std::set<CKeyID> set_address;
for (const auto& mi : mapCryptedKeys) {
set_address.insert(mi.first);
}
return set_address;
}
bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
{
LOCK(cs_KeyStore);
if (!mapCryptedKeys.empty() || IsCrypted())
return false;
fUseCrypto = true;
for (const KeyMap::value_type& mKey : mapKeys)
{
const CKey &key = mKey.second;
CPubKey vchPubKey = key.GetPubKey();
CKeyingMaterial vchSecret(key.begin(), key.end());
std::vector<unsigned char> vchCryptedSecret;
if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
return false;
if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
return false;
}
mapKeys.clear();
return true;
}

View file

@ -5,9 +5,9 @@
#ifndef BITCOIN_WALLET_CRYPTER_H #ifndef BITCOIN_WALLET_CRYPTER_H
#define BITCOIN_WALLET_CRYPTER_H #define BITCOIN_WALLET_CRYPTER_H
#include <keystore.h>
#include <serialize.h> #include <serialize.h>
#include <support/allocators/secure.h> #include <support/allocators/secure.h>
#include <script/signingprovider.h>
#include <atomic> #include <atomic>
@ -109,54 +109,8 @@ public:
} }
}; };
/** Keystore which keeps the private keys encrypted. bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext);
* It derives from the basic key store, which is used if no encryption is active. bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext);
*/ bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key);
class CCryptoKeyStore : public CBasicKeyStore
{
private:
CKeyingMaterial vMasterKey GUARDED_BY(cs_KeyStore);
//! if fUseCrypto is true, mapKeys must be empty
//! if fUseCrypto is false, vMasterKey must be empty
std::atomic<bool> fUseCrypto;
//! keeps track of whether Unlock has run a thorough check before
bool fDecryptionThoroughlyChecked;
protected:
using CryptedKeyMap = std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char>>>;
bool SetCrypted();
//! will encrypt previously unencrypted keys
bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys = false);
CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore);
public:
CCryptoKeyStore() : fUseCrypto(false), fDecryptionThoroughlyChecked(false)
{
}
bool IsCrypted() const { return fUseCrypto; }
bool IsLocked() const;
bool Lock();
virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override;
bool HaveKey(const CKeyID &address) const override;
bool GetKey(const CKeyID &address, CKey& keyOut) const override;
bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
std::set<CKeyID> GetKeys() const override;
/**
* Wallet status (encrypted, locked) changed.
* Note: Called without locks held.
*/
boost::signals2::signal<void (CCryptoKeyStore* wallet)> NotifyStatusChanged;
};
#endif // BITCOIN_WALLET_CRYPTER_H #endif // BITCOIN_WALLET_CRYPTER_H

View file

@ -8,6 +8,7 @@
#include <key.h> #include <key.h>
#include <script/script.h> #include <script/script.h>
#include <script/sign.h> #include <script/sign.h>
#include <script/signingprovider.h>
#include <wallet/wallet.h> #include <wallet/wallet.h>
typedef std::vector<unsigned char> valtype; typedef std::vector<unsigned char> valtype;

View file

@ -52,6 +52,14 @@ static inline bool GetAvoidReuseFlag(CWallet * const pwallet, const UniValue& pa
return avoid_reuse; return avoid_reuse;
} }
/** Checks if a CKey is in the given CWallet compressed or otherwise*/
bool HaveKey(const CWallet& wallet, const CKey& key)
{
CKey key2;
key2.Set(key.begin(), key.end(), !key.IsCompressed());
return wallet.HaveKey(key.GetPubKey().GetID()) || wallet.HaveKey(key2.GetPubKey().GetID());
}
bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name) bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name)
{ {
if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) { if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {

View file

@ -489,7 +489,7 @@ static size_t CalculateNestedKeyhashInputSize(bool use_max_sig)
CScript script_pubkey = CScript() << OP_HASH160 << std::vector<unsigned char>(script_id.begin(), script_id.end()) << OP_EQUAL; CScript script_pubkey = CScript() << OP_HASH160 << std::vector<unsigned char>(script_id.begin(), script_id.end()) << OP_EQUAL;
// Add inner-script to key store and key to watchonly // Add inner-script to key store and key to watchonly
CBasicKeyStore keystore; FillableSigningProvider keystore;
keystore.AddCScript(inner_script); keystore.AddCScript(inner_script);
keystore.AddKeyPubKey(key, pubkey); keystore.AddKeyPubKey(key, pubkey);

View file

@ -13,13 +13,13 @@
#include <interfaces/wallet.h> #include <interfaces/wallet.h>
#include <key.h> #include <key.h>
#include <key_io.h> #include <key_io.h>
#include <keystore.h>
#include <policy/fees.h> #include <policy/fees.h>
#include <policy/policy.h> #include <policy/policy.h>
#include <primitives/block.h> #include <primitives/block.h>
#include <primitives/transaction.h> #include <primitives/transaction.h>
#include <script/descriptor.h> #include <script/descriptor.h>
#include <script/script.h> #include <script/script.h>
#include <script/signingprovider.h>
#include <util/bip32.h> #include <util/bip32.h>
#include <util/error.h> #include <util/error.h>
#include <util/fees.h> #include <util/fees.h>
@ -358,14 +358,14 @@ bool CWallet::AddKeyPubKeyWithDB(WalletBatch& batch, const CKey& secret, const C
// Make sure we aren't adding private keys to private key disabled wallets // Make sure we aren't adding private keys to private key disabled wallets
assert(!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)); assert(!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
// CCryptoKeyStore has no concept of wallet databases, but calls AddCryptedKey // FillableSigningProvider has no concept of wallet databases, but calls AddCryptedKey
// which is overridden below. To avoid flushes, the database handle is // which is overridden below. To avoid flushes, the database handle is
// tunneled through to it. // tunneled through to it.
bool needsDB = !encrypted_batch; bool needsDB = !encrypted_batch;
if (needsDB) { if (needsDB) {
encrypted_batch = &batch; encrypted_batch = &batch;
} }
if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey)) { if (!AddKeyPubKeyInner(secret, pubkey)) {
if (needsDB) encrypted_batch = nullptr; if (needsDB) encrypted_batch = nullptr;
return false; return false;
} }
@ -400,7 +400,7 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
const std::vector<unsigned char> &vchCryptedSecret) const std::vector<unsigned char> &vchCryptedSecret)
{ {
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret)) if (!AddCryptedKeyInner(vchPubKey, vchCryptedSecret))
return false; return false;
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
@ -468,7 +468,7 @@ void CWallet::UpgradeKeyMetadata()
bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{ {
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); return AddCryptedKeyInner(vchPubKey, vchCryptedSecret);
} }
/** /**
@ -495,7 +495,7 @@ bool CWallet::AddCScript(const CScript& redeemScript)
bool CWallet::AddCScriptWithDB(WalletBatch& batch, const CScript& redeemScript) bool CWallet::AddCScriptWithDB(WalletBatch& batch, const CScript& redeemScript)
{ {
if (!CCryptoKeyStore::AddCScript(redeemScript)) if (!FillableSigningProvider::AddCScript(redeemScript))
return false; return false;
if (batch.WriteCScript(Hash160(redeemScript), redeemScript)) { if (batch.WriteCScript(Hash160(redeemScript), redeemScript)) {
UnsetWalletFlagWithDB(batch, WALLET_FLAG_BLANK_WALLET); UnsetWalletFlagWithDB(batch, WALLET_FLAG_BLANK_WALLET);
@ -516,12 +516,40 @@ bool CWallet::LoadCScript(const CScript& redeemScript)
return true; return true;
} }
return CCryptoKeyStore::AddCScript(redeemScript); return FillableSigningProvider::AddCScript(redeemScript);
}
static bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut)
{
//TODO: Use Solver to extract this?
CScript::const_iterator pc = dest.begin();
opcodetype opcode;
std::vector<unsigned char> vch;
if (!dest.GetOp(pc, opcode, vch) || !CPubKey::ValidSize(vch))
return false;
pubKeyOut = CPubKey(vch);
if (!pubKeyOut.IsFullyValid())
return false;
if (!dest.GetOp(pc, opcode, vch) || opcode != OP_CHECKSIG || dest.GetOp(pc, opcode, vch))
return false;
return true;
}
bool CWallet::AddWatchOnlyInMem(const CScript &dest)
{
LOCK(cs_KeyStore);
setWatchOnly.insert(dest);
CPubKey pubKey;
if (ExtractPubKey(dest, pubKey)) {
mapWatchKeys[pubKey.GetID()] = pubKey;
ImplicitlyLearnRelatedKeyScripts(pubKey);
}
return true;
} }
bool CWallet::AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest) bool CWallet::AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest)
{ {
if (!CCryptoKeyStore::AddWatchOnly(dest)) if (!AddWatchOnlyInMem(dest))
return false; return false;
const CKeyMetadata& meta = m_script_metadata[CScriptID(dest)]; const CKeyMetadata& meta = m_script_metadata[CScriptID(dest)];
UpdateTimeFirstKey(meta.nCreateTime); UpdateTimeFirstKey(meta.nCreateTime);
@ -554,8 +582,17 @@ bool CWallet::AddWatchOnly(const CScript& dest, int64_t nCreateTime)
bool CWallet::RemoveWatchOnly(const CScript &dest) bool CWallet::RemoveWatchOnly(const CScript &dest)
{ {
AssertLockHeld(cs_wallet); AssertLockHeld(cs_wallet);
if (!CCryptoKeyStore::RemoveWatchOnly(dest)) {
return false; LOCK(cs_KeyStore);
setWatchOnly.erase(dest);
CPubKey pubKey;
if (ExtractPubKey(dest, pubKey)) {
mapWatchKeys.erase(pubKey.GetID());
}
// Related CScripts are not removed; having superfluous scripts around is
// harmless (see comment in ImplicitlyLearnRelatedKeyScripts).
}
if (!HaveWatchOnly()) if (!HaveWatchOnly())
NotifyWatchonlyChanged(false); NotifyWatchonlyChanged(false);
if (!WalletBatch(*database).EraseWatchOnly(dest)) if (!WalletBatch(*database).EraseWatchOnly(dest))
@ -566,7 +603,19 @@ bool CWallet::RemoveWatchOnly(const CScript &dest)
bool CWallet::LoadWatchOnly(const CScript &dest) bool CWallet::LoadWatchOnly(const CScript &dest)
{ {
return CCryptoKeyStore::AddWatchOnly(dest); return AddWatchOnlyInMem(dest);
}
bool CWallet::HaveWatchOnly(const CScript &dest) const
{
LOCK(cs_KeyStore);
return setWatchOnly.count(dest) > 0;
}
bool CWallet::HaveWatchOnly() const
{
LOCK(cs_KeyStore);
return (!setWatchOnly.empty());
} }
bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_keys) bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_keys)
@ -582,7 +631,7 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_key
return false; return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey)) if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
continue; // try another master key continue; // try another master key
if (CCryptoKeyStore::Unlock(_vMasterKey, accept_no_keys)) { if (Unlock(_vMasterKey, accept_no_keys)) {
// Now that we've unlocked, upgrade the key metadata // Now that we've unlocked, upgrade the key metadata
UpgradeKeyMetadata(); UpgradeKeyMetadata();
return true; return true;
@ -608,7 +657,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
return false; return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey)) if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
return false; return false;
if (CCryptoKeyStore::Unlock(_vMasterKey)) if (Unlock(_vMasterKey))
{ {
int64_t nStartTime = GetTimeMillis(); int64_t nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod); crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
@ -4681,3 +4730,203 @@ bool CWallet::AddKeyOriginWithDB(WalletBatch& batch, const CPubKey& pubkey, cons
mapKeyMetadata[pubkey.GetID()].hdKeypath = WriteHDKeypath(info.path); mapKeyMetadata[pubkey.GetID()].hdKeypath = WriteHDKeypath(info.path);
return batch.WriteKeyMetadata(mapKeyMetadata[pubkey.GetID()], pubkey, true); return batch.WriteKeyMetadata(mapKeyMetadata[pubkey.GetID()], pubkey, true);
} }
bool CWallet::SetCrypted()
{
LOCK(cs_KeyStore);
if (fUseCrypto)
return true;
if (!mapKeys.empty())
return false;
fUseCrypto = true;
return true;
}
bool CWallet::IsLocked() const
{
if (!IsCrypted()) {
return false;
}
LOCK(cs_KeyStore);
return vMasterKey.empty();
}
bool CWallet::Lock()
{
if (!SetCrypted())
return false;
{
LOCK(cs_KeyStore);
vMasterKey.clear();
}
NotifyStatusChanged(this);
return true;
}
bool CWallet::Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys)
{
{
LOCK(cs_KeyStore);
if (!SetCrypted())
return false;
bool keyPass = mapCryptedKeys.empty(); // Always pass when there are no encrypted keys
bool keyFail = false;
CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
for (; mi != mapCryptedKeys.end(); ++mi)
{
const CPubKey &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
CKey key;
if (!DecryptKey(vMasterKeyIn, vchCryptedSecret, vchPubKey, key))
{
keyFail = true;
break;
}
keyPass = true;
if (fDecryptionThoroughlyChecked)
break;
}
if (keyPass && keyFail)
{
LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
throw std::runtime_error("Error unlocking wallet: some keys decrypt but not all. Your wallet file may be corrupt.");
}
if (keyFail || (!keyPass && !accept_no_keys))
return false;
vMasterKey = vMasterKeyIn;
fDecryptionThoroughlyChecked = true;
}
NotifyStatusChanged(this);
return true;
}
bool CWallet::HaveKey(const CKeyID &address) const
{
LOCK(cs_KeyStore);
if (!IsCrypted()) {
return FillableSigningProvider::HaveKey(address);
}
return mapCryptedKeys.count(address) > 0;
}
bool CWallet::GetKey(const CKeyID &address, CKey& keyOut) const
{
LOCK(cs_KeyStore);
if (!IsCrypted()) {
return FillableSigningProvider::GetKey(address, keyOut);
}
CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
if (mi != mapCryptedKeys.end())
{
const CPubKey &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
}
return false;
}
bool CWallet::GetWatchPubKey(const CKeyID &address, CPubKey &pubkey_out) const
{
LOCK(cs_KeyStore);
WatchKeyMap::const_iterator it = mapWatchKeys.find(address);
if (it != mapWatchKeys.end()) {
pubkey_out = it->second;
return true;
}
return false;
}
bool CWallet::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
{
LOCK(cs_KeyStore);
if (!IsCrypted()) {
if (!FillableSigningProvider::GetPubKey(address, vchPubKeyOut)) {
return GetWatchPubKey(address, vchPubKeyOut);
}
return true;
}
CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
if (mi != mapCryptedKeys.end())
{
vchPubKeyOut = (*mi).second.first;
return true;
}
// Check for watch-only pubkeys
return GetWatchPubKey(address, vchPubKeyOut);
}
std::set<CKeyID> CWallet::GetKeys() const
{
LOCK(cs_KeyStore);
if (!IsCrypted()) {
return FillableSigningProvider::GetKeys();
}
std::set<CKeyID> set_address;
for (const auto& mi : mapCryptedKeys) {
set_address.insert(mi.first);
}
return set_address;
}
bool CWallet::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
{
LOCK(cs_KeyStore);
if (!mapCryptedKeys.empty() || IsCrypted())
return false;
fUseCrypto = true;
for (const KeyMap::value_type& mKey : mapKeys)
{
const CKey &key = mKey.second;
CPubKey vchPubKey = key.GetPubKey();
CKeyingMaterial vchSecret(key.begin(), key.end());
std::vector<unsigned char> vchCryptedSecret;
if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
return false;
if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
return false;
}
mapKeys.clear();
return true;
}
bool CWallet::AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey)
{
LOCK(cs_KeyStore);
if (!IsCrypted()) {
return FillableSigningProvider::AddKeyPubKey(key, pubkey);
}
if (IsLocked()) {
return false;
}
std::vector<unsigned char> vchCryptedSecret;
CKeyingMaterial vchSecret(key.begin(), key.end());
if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret)) {
return false;
}
if (!AddCryptedKey(pubkey, vchCryptedSecret)) {
return false;
}
return true;
}
bool CWallet::AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{
LOCK(cs_KeyStore);
if (!SetCrypted()) {
return false;
}
mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
ImplicitlyLearnRelatedKeyScripts(vchPubKey);
return true;
}

View file

@ -35,6 +35,8 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <boost/signals2/signal.hpp>
//! Explicitly unload and delete the wallet. //! Explicitly unload and delete the wallet.
//! Blocks the current thread after signaling the unload intent so that all //! Blocks the current thread after signaling the unload intent so that all
//! wallet clients release the wallet. //! wallet clients release the wallet.
@ -719,9 +721,35 @@ class WalletRescanReserver; //forward declarations for ScanForWalletTransactions
* A CWallet is an extension of a keystore, which also maintains a set of transactions and balances, * A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
* and provides the ability to create new transactions. * and provides the ability to create new transactions.
*/ */
class CWallet final : public CCryptoKeyStore, private interfaces::Chain::Notifications class CWallet final : public FillableSigningProvider, private interfaces::Chain::Notifications
{ {
private: private:
CKeyingMaterial vMasterKey GUARDED_BY(cs_KeyStore);
//! if fUseCrypto is true, mapKeys must be empty
//! if fUseCrypto is false, vMasterKey must be empty
std::atomic<bool> fUseCrypto;
//! keeps track of whether Unlock has run a thorough check before
bool fDecryptionThoroughlyChecked;
using CryptedKeyMap = std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char>>>;
using WatchOnlySet = std::set<CScript>;
using WatchKeyMap = std::map<CKeyID, CPubKey>;
bool SetCrypted();
//! will encrypt previously unencrypted keys
bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys = false);
CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore);
WatchOnlySet setWatchOnly GUARDED_BY(cs_KeyStore);
WatchKeyMap mapWatchKeys GUARDED_BY(cs_KeyStore);
bool AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
bool AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey);
std::atomic<bool> fAbortRescan{false}; std::atomic<bool> fAbortRescan{false};
std::atomic<bool> fScanningWallet{false}; // controlled by WalletRescanReserver std::atomic<bool> fScanningWallet{false}; // controlled by WalletRescanReserver
std::atomic<int64_t> m_scanning_start{0}; std::atomic<int64_t> m_scanning_start{0};
@ -804,8 +832,9 @@ private:
* of the other AddWatchOnly which accepts a timestamp and sets * of the other AddWatchOnly which accepts a timestamp and sets
* nTimeFirstKey more intelligently for more efficient rescans. * nTimeFirstKey more intelligently for more efficient rescans.
*/ */
bool AddWatchOnly(const CScript& dest) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool AddWatchOnly(const CScript& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool AddWatchOnlyInMem(const CScript &dest);
/** Add a KeyOriginInfo to the wallet */ /** Add a KeyOriginInfo to the wallet */
bool AddKeyOriginWithDB(WalletBatch& batch, const CPubKey& pubkey, const KeyOriginInfo& info); bool AddKeyOriginWithDB(WalletBatch& batch, const CPubKey& pubkey, const KeyOriginInfo& info);
@ -892,7 +921,9 @@ public:
/** Construct wallet with specified name and database implementation. */ /** Construct wallet with specified name and database implementation. */
CWallet(interfaces::Chain* chain, const WalletLocation& location, std::unique_ptr<WalletDatabase> database) CWallet(interfaces::Chain* chain, const WalletLocation& location, std::unique_ptr<WalletDatabase> database)
: m_chain(chain), : fUseCrypto(false),
fDecryptionThoroughlyChecked(false),
m_chain(chain),
m_location(location), m_location(location),
database(std::move(database)) database(std::move(database))
{ {
@ -906,6 +937,10 @@ public:
encrypted_batch = nullptr; encrypted_batch = nullptr;
} }
bool IsCrypted() const { return fUseCrypto; }
bool IsLocked() const;
bool Lock();
std::map<uint256, CWalletTx> mapWallet GUARDED_BY(cs_wallet); std::map<uint256, CWalletTx> mapWallet GUARDED_BY(cs_wallet);
typedef std::multimap<int64_t, CWalletTx*> TxItems; typedef std::multimap<int64_t, CWalletTx*> TxItems;
@ -988,7 +1023,7 @@ public:
//! Adds a key to the store, and saves it to disk. //! Adds a key to the store, and saves it to disk.
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Adds a key to the store, without saving it to disk (used by LoadWallet) //! Adds a key to the store, without saving it to disk (used by LoadWallet)
bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); } bool LoadKey(const CKey& key, const CPubKey &pubkey) { return AddKeyPubKeyInner(key, pubkey); }
//! Load metadata (used by LoadWallet) //! Load metadata (used by LoadWallet)
void LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &metadata) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); void LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &metadata) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &metadata) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); void LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &metadata) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@ -999,9 +1034,13 @@ public:
void UpdateTimeFirstKey(int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); void UpdateTimeFirstKey(int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Adds an encrypted key to the store, and saves it to disk. //! Adds an encrypted key to the store, and saves it to disk.
bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) override; bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
//! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) //! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret); bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
bool GetKey(const CKeyID &address, CKey& keyOut) const override;
bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
bool HaveKey(const CKeyID &address) const override;
std::set<CKeyID> GetKeys() const override;
bool AddCScript(const CScript& redeemScript) override; bool AddCScript(const CScript& redeemScript) override;
bool LoadCScript(const CScript& redeemScript); bool LoadCScript(const CScript& redeemScript);
@ -1018,9 +1057,15 @@ public:
//! Adds a watch-only address to the store, and saves it to disk. //! Adds a watch-only address to the store, and saves it to disk.
bool AddWatchOnly(const CScript& dest, int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool AddWatchOnly(const CScript& dest, int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool RemoveWatchOnly(const CScript &dest) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool RemoveWatchOnly(const CScript &dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Adds a watch-only address to the store, without saving it to disk (used by LoadWallet) //! Adds a watch-only address to the store, without saving it to disk (used by LoadWallet)
bool LoadWatchOnly(const CScript &dest); bool LoadWatchOnly(const CScript &dest);
//! Returns whether the watch-only script is in the wallet
bool HaveWatchOnly(const CScript &dest) const;
//! Returns whether there are any watch-only things in the wallet
bool HaveWatchOnly() const;
//! Fetches a pubkey from mapWatchKeys if it exists there
bool GetWatchPubKey(const CKeyID &address, CPubKey &pubkey_out) const;
//! Holds a timestamp at which point the wallet is scheduled (externally) to be relocked. Caller must arrange for actual relocking to occur via Lock(). //! Holds a timestamp at which point the wallet is scheduled (externally) to be relocked. Caller must arrange for actual relocking to occur via Lock().
int64_t nRelockTime = 0; int64_t nRelockTime = 0;
@ -1247,6 +1292,12 @@ public:
/** Keypool has new keys */ /** Keypool has new keys */
boost::signals2::signal<void ()> NotifyCanGetAddressesChanged; boost::signals2::signal<void ()> NotifyCanGetAddressesChanged;
/**
* Wallet status (encrypted, locked) changed.
* Note: Called without locks held.
*/
boost::signals2::signal<void (CWallet* wallet)> NotifyStatusChanged;
/** Inquire whether this wallet broadcasts transactions. */ /** Inquire whether this wallet broadcasts transactions. */
bool GetBroadcastTransactions() const { return fBroadcastTransactions; } bool GetBroadcastTransactions() const { return fBroadcastTransactions; }
/** Set whether this wallet broadcasts transactions. */ /** Set whether this wallet broadcasts transactions. */
@ -1311,7 +1362,7 @@ public:
/** /**
* Explicitly make the wallet learn the related scripts for outputs to the * Explicitly make the wallet learn the related scripts for outputs to the
* given key. This is purely to make the wallet file compatible with older * given key. This is purely to make the wallet file compatible with older
* software, as CBasicKeyStore automatically does this implicitly for all * software, as FillableSigningProvider automatically does this implicitly for all
* keys now. * keys now.
*/ */
void LearnRelatedScripts(const CPubKey& key, OutputType); void LearnRelatedScripts(const CPubKey& key, OutputType);