mirror of
https://github.com/dashpay/dash.git
synced 2024-12-24 19:42:46 +01:00
* Add HaveKey and HaveCScript to SigningProvider * Remove CKeyStore and squash into CBasicKeyStore * Move HaveKey static function from keystore to rpcwallet where it is used * scripted-diff: rename CBasicKeyStore to FillableSigningProvider -BEGIN VERIFY SCRIPT- git grep -l "CBasicKeyStore" | xargs sed -i -e 's/CBasicKeyStore/FillableSigningProvider/g' -END VERIFY SCRIPT- * Move KeyOriginInfo to its own header file * Move various SigningProviders to signingprovider.{cpp,h} Moves all of the various SigningProviders out of sign.{cpp,h} and keystore.{cpp,h}. As such, keystore.{cpp,h} is also removed. Includes and the Makefile are updated to reflect this. Includes were largely changed using: git grep -l "keystore.h" | xargs sed -i -e 's;keystore.h;script/signingprovider.h;g' * Remove CCryptoKeyStore and move all of it's functionality into CWallet Instead of having a separate CCryptoKeyStore that handles the encryption stuff, just roll it all into CWallet. * Fixed cases of mess CWallet functions with CCryptoKeyStore and conflicts * Move WatchOnly stuff from SigningProvider to CWallet * Fixes for lint cirtular dependencies to calm linter Co-authored-by: Andrew Chow <achow101-github@achow101.com>
This commit is contained in:
parent
eefdae1a53
commit
0a951622f1
@ -445,7 +445,7 @@ reported in the `debug.log` file.
|
||||
|
||||
Re-architecting the core code so there are better-defined interfaces
|
||||
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).
|
||||
|
||||
Threads
|
||||
|
@ -195,7 +195,6 @@ BITCOIN_CORE_H = \
|
||||
interfaces/wallet.h \
|
||||
key.h \
|
||||
key_io.h \
|
||||
keystore.h \
|
||||
dbwrapper.h \
|
||||
limitedmap.h \
|
||||
llmq/quorums.h \
|
||||
@ -263,8 +262,10 @@ BITCOIN_CORE_H = \
|
||||
saltedhasher.h \
|
||||
scheduler.h \
|
||||
script/descriptor.h \
|
||||
script/keyorigin.h \
|
||||
script/sigcache.h \
|
||||
script/sign.h \
|
||||
script/signingprovider.h \
|
||||
script/standard.h \
|
||||
shutdown.h \
|
||||
spork.h \
|
||||
@ -652,7 +653,6 @@ libdash_common_a_SOURCES = \
|
||||
hdchain.cpp \
|
||||
key.cpp \
|
||||
key_io.cpp \
|
||||
keystore.cpp \
|
||||
merkleblock.cpp \
|
||||
netaddress.cpp \
|
||||
netbase.cpp \
|
||||
@ -667,6 +667,7 @@ libdash_common_a_SOURCES = \
|
||||
scheduler.cpp \
|
||||
script/descriptor.cpp \
|
||||
script/sign.cpp \
|
||||
script/signingprovider.cpp \
|
||||
script/standard.cpp \
|
||||
versionbitsinfo.cpp \
|
||||
warnings.cpp \
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <bench/bench.h>
|
||||
#include <coins.h>
|
||||
#include <policy/policy.h>
|
||||
#include <wallet/crypter.h>
|
||||
#include <script/signingprovider.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
// paid to a TX_PUBKEYHASH.
|
||||
//
|
||||
static std::vector<CMutableTransaction>
|
||||
SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
|
||||
SetupDummyInputs(FillableSigningProvider& keystoreRet, CCoinsViewCache& coinsRet)
|
||||
{
|
||||
std::vector<CMutableTransaction> dummyTransactions;
|
||||
dummyTransactions.resize(2);
|
||||
@ -58,7 +58,7 @@ static void CCoinsCaching(benchmark::Bench& bench)
|
||||
const ECCVerifyHandle verify_handle;
|
||||
ECC_Start();
|
||||
|
||||
CBasicKeyStore keystore;
|
||||
FillableSigningProvider keystore;
|
||||
CCoinsView coinsDummy;
|
||||
CCoinsViewCache coins(&coinsDummy);
|
||||
std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
|
||||
|
@ -12,10 +12,10 @@
|
||||
#include <consensus/consensus.h>
|
||||
#include <core_io.h>
|
||||
#include <key_io.h>
|
||||
#include <keystore.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <script/script.h>
|
||||
#include <script/sign.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <univalue.h>
|
||||
#include <util/moneystr.h>
|
||||
#include <util/strencodings.h>
|
||||
@ -515,7 +515,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
|
||||
|
||||
if (!registers.count("privatekeys"))
|
||||
throw std::runtime_error("privatekeys register variable must be set.");
|
||||
CBasicKeyStore tempKeystore;
|
||||
FillableSigningProvider tempKeystore;
|
||||
UniValue keysObj = registers["privatekeys"];
|
||||
|
||||
for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) {
|
||||
@ -589,7 +589,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);
|
||||
|
||||
|
@ -518,7 +518,7 @@ public:
|
||||
}
|
||||
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
|
||||
{
|
||||
|
142
src/keystore.cpp
142
src/keystore.cpp
@ -1,142 +0,0 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2015 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <keystore.h>
|
||||
|
||||
#include <util/system.h>
|
||||
|
||||
bool CBasicKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
|
||||
{
|
||||
CKey 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;
|
||||
}
|
||||
vchPubKeyOut = key.GetPubKey();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
mapKeys[pubkey.GetID()] = key;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBasicKeyStore::HaveKey(const CKeyID &address) const
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
return mapKeys.count(address) > 0;
|
||||
}
|
||||
|
||||
std::set<CKeyID> CBasicKeyStore::GetKeys() const
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
std::set<CKeyID> set_address;
|
||||
for (const auto& mi : mapKeys) {
|
||||
set_address.insert(mi.first);
|
||||
}
|
||||
return set_address;
|
||||
}
|
||||
|
||||
bool CBasicKeyStore::GetKey(const CKeyID &address, CKey &keyOut) const
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
KeyMap::const_iterator mi = mapKeys.find(address);
|
||||
if (mi != mapKeys.end()) {
|
||||
keyOut = mi->second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CBasicKeyStore::AddCScript(const CScript& redeemScript)
|
||||
{
|
||||
if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
|
||||
return error("CBasicKeyStore::AddCScript(): redeemScripts > %i bytes are invalid", MAX_SCRIPT_ELEMENT_SIZE);
|
||||
|
||||
LOCK(cs_KeyStore);
|
||||
mapScripts[CScriptID(redeemScript)] = redeemScript;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBasicKeyStore::HaveCScript(const CScriptID& hash) const
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
return mapScripts.count(hash) > 0;
|
||||
}
|
||||
|
||||
std::set<CScriptID> CBasicKeyStore::GetCScripts() const
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
std::set<CScriptID> set_script;
|
||||
for (const auto& mi : mapScripts) {
|
||||
set_script.insert(mi.first);
|
||||
}
|
||||
return set_script;
|
||||
}
|
||||
|
||||
bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
ScriptMap::const_iterator mi = mapScripts.find(hash);
|
||||
if (mi != mapScripts.end())
|
||||
{
|
||||
redeemScriptOut = (*mi).second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut)
|
||||
{
|
||||
std::vector<std::vector<unsigned char>> solutions;
|
||||
return Solver(dest, solutions) == TX_PUBKEY &&
|
||||
(pubKeyOut = CPubKey(solutions[0])).IsFullyValid();
|
||||
}
|
||||
|
||||
bool CBasicKeyStore::AddWatchOnly(const CScript &dest)
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
setWatchOnly.insert(dest);
|
||||
CPubKey pubKey;
|
||||
if (ExtractPubKey(dest, pubKey))
|
||||
mapWatchKeys[pubKey.GetID()] = 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());
|
||||
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());
|
||||
}
|
||||
|
||||
bool CBasicKeyStore::GetHDChain(CHDChain& hdChainRet) const
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
hdChainRet = hdChain;
|
||||
return !hdChain.IsNull();
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2015 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 <hdchain.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);
|
||||
/* the HD chain data model*/
|
||||
CHDChain hdChain GUARDED_BY(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;
|
||||
|
||||
virtual bool GetHDChain(CHDChain& hdChainRet) const;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_KEYSTORE_H
|
@ -11,6 +11,7 @@
|
||||
#include <primitives/transaction.h>
|
||||
#include <pubkey.h>
|
||||
#include <script/sign.h>
|
||||
#include <script/signingprovider.h>
|
||||
|
||||
// Magic bytes
|
||||
static constexpr uint8_t PSBT_MAGIC_BYTES[5] = {'p', 's', 'b', 't', 0xff};
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include <index/txindex.h>
|
||||
#include <init.h>
|
||||
#include <key_io.h>
|
||||
#include <keystore.h>
|
||||
#include <merkleblock.h>
|
||||
#include <node/coin.h>
|
||||
#include <node/context.h>
|
||||
@ -28,6 +27,7 @@
|
||||
#include <rpc/util.h>
|
||||
#include <script/script.h>
|
||||
#include <script/sign.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <script/standard.h>
|
||||
#include <txmempool.h>
|
||||
#include <uint256.h>
|
||||
@ -760,7 +760,7 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
|
||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
|
||||
}
|
||||
|
||||
CBasicKeyStore keystore;
|
||||
FillableSigningProvider keystore;
|
||||
const UniValue& keys = request.params[1].get_array();
|
||||
for (unsigned int idx = 0; idx < keys.size(); ++idx) {
|
||||
UniValue k = keys[idx];
|
||||
|
@ -9,11 +9,11 @@
|
||||
#include <core_io.h>
|
||||
#include <interfaces/chain.h>
|
||||
#include <key_io.h>
|
||||
#include <keystore.h>
|
||||
#include <policy/policy.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <rpc/request.h>
|
||||
#include <rpc/util.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <univalue.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <validation.h>
|
||||
@ -129,7 +129,7 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::
|
||||
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:
|
||||
if (!prevTxsUnival.isNull()) {
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
#include <map>
|
||||
|
||||
class CBasicKeyStore;
|
||||
class FillableSigningProvider;
|
||||
class UniValue;
|
||||
struct CMutableTransaction;
|
||||
class Coin;
|
||||
@ -24,7 +24,7 @@ class COutPoint;
|
||||
* @param hashType The signature hash type
|
||||
* @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 */
|
||||
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime);
|
||||
|
@ -4,10 +4,10 @@
|
||||
|
||||
#include <chainparamsbase.h>
|
||||
#include <key_io.h>
|
||||
#include <keystore.h>
|
||||
#include <pubkey.h>
|
||||
#include <rpc/util.h>
|
||||
#include <script/descriptor.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <tinyformat.h>
|
||||
#include <util/system.h>
|
||||
#include <util/strencodings.h>
|
||||
@ -190,8 +190,8 @@ CPubKey HexToPubKey(const std::string& hex_in)
|
||||
return vchPubKey;
|
||||
}
|
||||
|
||||
// Retrieves a public key for an address from the given CKeyStore
|
||||
CPubKey AddrToPubKey(CKeyStore* const keystore, const std::string& addr_in)
|
||||
// Retrieves a public key for an address from the given FillableSigningProvider
|
||||
CPubKey AddrToPubKey(FillableSigningProvider* const keystore, const std::string& addr_in)
|
||||
{
|
||||
CTxDestination dest = DecodeDestination(addr_in);
|
||||
if (!IsValidDestination(dest)) {
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <rpc/request.h>
|
||||
#include <script/script.h>
|
||||
#include <script/sign.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <script/standard.h>
|
||||
#include <univalue.h>
|
||||
#include <util/check.h>
|
||||
@ -29,7 +30,7 @@
|
||||
*/
|
||||
extern const std::string UNIX_EPOCH_TIME;
|
||||
|
||||
class CKeyStore;
|
||||
class FillableSigningProvider;
|
||||
class FillableSigningProvider;
|
||||
class CPubKey;
|
||||
class CScript;
|
||||
@ -83,7 +84,7 @@ extern std::string HelpExampleCli(const std::string& methodname, const std::stri
|
||||
extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args);
|
||||
|
||||
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);
|
||||
CScript CreateMultisigRedeemscript(const int required, const std::vector<CPubKey>& pubkeys);
|
||||
|
||||
UniValue DescribeAddress(const CTxDestination& dest);
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <script/script.h>
|
||||
#include <script/sign.h>
|
||||
#include <script/signingprovider.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
34
src/script/keyorigin.h
Normal file
34
src/script/keyorigin.h
Normal file
@ -0,0 +1,34 @@
|
||||
// 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;
|
||||
}
|
||||
|
||||
SERIALIZE_METHODS(KeyOriginInfo, obj)
|
||||
{
|
||||
READWRITE(obj.fingerprint, obj.path);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
memset(fingerprint, 0, 4);
|
||||
path.clear();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // BITCOIN_SCRIPT_KEYORIGIN_H
|
@ -8,6 +8,7 @@
|
||||
#include <key.h>
|
||||
#include <policy/policy.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <script/standard.h>
|
||||
#include <uint256.h>
|
||||
|
||||
@ -362,22 +363,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_MAXIMUM_SIGNATURE_CREATOR = DummySignatureCreator(33, 32);
|
||||
const SigningProvider& DUMMY_SIGNING_PROVIDER = SigningProvider();
|
||||
|
||||
bool IsSolvable(const SigningProvider& provider, const CScript& script)
|
||||
{
|
||||
@ -393,51 +382,3 @@ bool IsSolvable(const SigningProvider& provider, const CScript& script)
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <hash.h>
|
||||
#include <pubkey.h>
|
||||
#include <script/interpreter.h>
|
||||
#include <script/keyorigin.h>
|
||||
#include <streams.h>
|
||||
|
||||
class CKey;
|
||||
@ -16,74 +17,10 @@ class CKeyID;
|
||||
class CScript;
|
||||
class CScriptID;
|
||||
class CTransaction;
|
||||
class SigningProvider;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
SERIALIZE_METHODS(KeyOriginInfo, obj)
|
||||
{
|
||||
READWRITE(obj.fingerprint, obj.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. */
|
||||
class BaseSignatureCreator {
|
||||
public:
|
||||
|
159
src/script/signingprovider.cpp
Normal file
159
src/script/signingprovider.cpp
Normal file
@ -0,0 +1,159 @@
|
||||
// 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.
|
||||
|
||||
#include <script/keyorigin.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <script/standard.h>
|
||||
|
||||
#include <util/system.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool FillableSigningProvider::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
|
||||
{
|
||||
CKey key;
|
||||
if (!GetKey(address, key)) {
|
||||
return false;
|
||||
}
|
||||
vchPubKeyOut = key.GetPubKey();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FillableSigningProvider::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
mapKeys[pubkey.GetID()] = key;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FillableSigningProvider::HaveKey(const CKeyID &address) const
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
return mapKeys.count(address) > 0;
|
||||
}
|
||||
|
||||
std::set<CKeyID> FillableSigningProvider::GetKeys() const
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
std::set<CKeyID> set_address;
|
||||
for (const auto& mi : mapKeys) {
|
||||
set_address.insert(mi.first);
|
||||
}
|
||||
return set_address;
|
||||
}
|
||||
|
||||
bool FillableSigningProvider::GetKey(const CKeyID &address, CKey &keyOut) const
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
KeyMap::const_iterator mi = mapKeys.find(address);
|
||||
if (mi != mapKeys.end()) {
|
||||
keyOut = mi->second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FillableSigningProvider::AddCScript(const CScript& redeemScript)
|
||||
{
|
||||
if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
|
||||
return error("FillableSigningProvider::AddCScript(): redeemScripts > %i bytes are invalid", MAX_SCRIPT_ELEMENT_SIZE);
|
||||
|
||||
LOCK(cs_KeyStore);
|
||||
mapScripts[CScriptID(redeemScript)] = redeemScript;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FillableSigningProvider::HaveCScript(const CScriptID& hash) const
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
return mapScripts.count(hash) > 0;
|
||||
}
|
||||
|
||||
std::set<CScriptID> FillableSigningProvider::GetCScripts() const
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
std::set<CScriptID> set_script;
|
||||
for (const auto& mi : mapScripts) {
|
||||
set_script.insert(mi.first);
|
||||
}
|
||||
return set_script;
|
||||
}
|
||||
|
||||
bool FillableSigningProvider::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
ScriptMap::const_iterator mi = mapScripts.find(hash);
|
||||
if (mi != mapScripts.end())
|
||||
{
|
||||
redeemScriptOut = (*mi).second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FillableSigningProvider::GetHDChain(CHDChain& hdChainRet) const
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
hdChainRet = hdChain;
|
||||
return !hdChain.IsNull();
|
||||
}
|
92
src/script/signingprovider.h
Normal file
92
src/script/signingprovider.h
Normal 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 <hdchain.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);
|
||||
/* the HD chain data model*/
|
||||
CHDChain hdChain GUARDED_BY(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;
|
||||
|
||||
virtual bool GetHDChain(CHDChain& hdChainRet) const;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_SCRIPT_SIGNINGPROVIDER_H
|
@ -8,7 +8,6 @@
|
||||
#include <pubkey.h>
|
||||
#include <script/script.h>
|
||||
|
||||
|
||||
typedef std::vector<unsigned char> valtype;
|
||||
|
||||
bool fAcceptDatacarrier = DEFAULT_ACCEPT_DATACARRIER;
|
||||
|
@ -6,12 +6,12 @@
|
||||
|
||||
#include <chainparams.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <keystore.h>
|
||||
#include <messagesigner.h>
|
||||
#include <miner.h>
|
||||
#include <netbase.h>
|
||||
#include <script/interpreter.h>
|
||||
#include <script/sign.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <script/standard.h>
|
||||
#include <validation.h>
|
||||
|
||||
@ -96,7 +96,7 @@ static void FundTransaction(CMutableTransaction& tx, SimpleUTXOMap& utoxs, const
|
||||
|
||||
static void SignTransaction(const CTxMemPool& mempool, CMutableTransaction& tx, const CKey& coinbaseKey)
|
||||
{
|
||||
CBasicKeyStore tempKeystore;
|
||||
FillableSigningProvider tempKeystore;
|
||||
tempKeystore.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
|
||||
|
||||
for (size_t i = 0; i < tx.vin.size(); i++) {
|
||||
|
@ -6,10 +6,11 @@
|
||||
|
||||
#include <banman.h>
|
||||
#include <chainparams.h>
|
||||
#include <keystore.h>
|
||||
#include <net.h>
|
||||
#include <net_processing.h>
|
||||
#include <script/sign.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <script/standard.h>
|
||||
#include <util/memory.h>
|
||||
#include <util/system.h>
|
||||
#include <util/time.h>
|
||||
@ -364,7 +365,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
|
||||
{
|
||||
CKey key;
|
||||
key.MakeNewKey(true);
|
||||
CBasicKeyStore keystore;
|
||||
FillableSigningProvider keystore;
|
||||
BOOST_CHECK(keystore.AddKey(key));
|
||||
|
||||
// 50 orphan transactions:
|
||||
|
@ -7,12 +7,12 @@
|
||||
#include <base58.h>
|
||||
#include <chainparams.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <keystore.h>
|
||||
#include <messagesigner.h>
|
||||
#include <netbase.h>
|
||||
#include <policy/policy.h>
|
||||
#include <script/interpreter.h>
|
||||
#include <script/sign.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <script/standard.h>
|
||||
#include <spork.h>
|
||||
#include <txmempool.h>
|
||||
@ -82,7 +82,7 @@ static void FundTransaction(CMutableTransaction& tx, SimpleUTXOMap& utoxs, const
|
||||
|
||||
static void SignTransaction(const CTxMemPool& mempool, CMutableTransaction& tx, const CKey& coinbaseKey)
|
||||
{
|
||||
CBasicKeyStore tempKeystore;
|
||||
FillableSigningProvider tempKeystore;
|
||||
tempKeystore.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
|
||||
|
||||
for (size_t i = 0; i < tx.vin.size(); i++) {
|
||||
|
@ -3,12 +3,12 @@
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <key.h>
|
||||
#include <keystore.h>
|
||||
#include <policy/policy.h>
|
||||
#include <script/script.h>
|
||||
#include <script/script_error.h>
|
||||
#include <script/interpreter.h>
|
||||
#include <script/sign.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <tinyformat.h>
|
||||
#include <uint256.h>
|
||||
#include <test/util/setup_common.h>
|
||||
@ -174,7 +174,7 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
|
||||
BOOST_AUTO_TEST_CASE(multisig_Sign)
|
||||
{
|
||||
// Test SignSignature() (and therefore the version of Solver() that signs transactions)
|
||||
CBasicKeyStore keystore;
|
||||
FillableSigningProvider keystore;
|
||||
CKey key[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
|
@ -4,13 +4,13 @@
|
||||
|
||||
#include <consensus/tx_verify.h>
|
||||
#include <key.h>
|
||||
#include <keystore.h>
|
||||
#include <validation.h>
|
||||
#include <policy/policy.h>
|
||||
#include <policy/settings.h>
|
||||
#include <script/script.h>
|
||||
#include <script/script_error.h>
|
||||
#include <script/sign.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <test/util/setup_common.h>
|
||||
|
||||
#include <vector>
|
||||
@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(sign)
|
||||
// scriptPubKey: HASH160 <hash> EQUAL
|
||||
|
||||
// Test SignSignature() (and therefore the version of Solver() that signs transactions)
|
||||
CBasicKeyStore keystore;
|
||||
FillableSigningProvider keystore;
|
||||
CKey key[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
@ -151,7 +151,7 @@ BOOST_AUTO_TEST_CASE(set)
|
||||
{
|
||||
LOCK(cs_main);
|
||||
// Test the CScript::Set* methods
|
||||
CBasicKeyStore keystore;
|
||||
FillableSigningProvider keystore;
|
||||
CKey key[4];
|
||||
std::vector<CPubKey> keys;
|
||||
for (int i = 0; i < 4; i++)
|
||||
@ -266,7 +266,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
|
||||
LOCK(cs_main);
|
||||
CCoinsView coinsDummy;
|
||||
CCoinsViewCache coins(&coinsDummy);
|
||||
CBasicKeyStore keystore;
|
||||
FillableSigningProvider keystore;
|
||||
CKey key[6];
|
||||
std::vector<CPubKey> keys;
|
||||
for (int i = 0; i < 6; i++)
|
||||
|
@ -3,8 +3,8 @@
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <key.h>
|
||||
#include <keystore.h>
|
||||
#include <script/script.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <script/standard.h>
|
||||
#include <test/util/setup_common.h>
|
||||
|
||||
|
@ -6,10 +6,10 @@
|
||||
|
||||
#include <core_io.h>
|
||||
#include <key.h>
|
||||
#include <keystore.h>
|
||||
#include <script/script.h>
|
||||
#include <script/script_error.h>
|
||||
#include <script/sign.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <rpc/util.h>
|
||||
#include <test/util/setup_common.h>
|
||||
@ -1113,7 +1113,7 @@ SignatureData CombineSignatures(const CTxOut& txout, const CMutableTransaction&
|
||||
BOOST_AUTO_TEST_CASE(script_combineSigs)
|
||||
{
|
||||
// Test the ProduceSignature's ability to combine signatures function
|
||||
CBasicKeyStore keystore;
|
||||
FillableSigningProvider keystore;
|
||||
std::vector<CKey> keys;
|
||||
std::vector<CPubKey> pubkeys;
|
||||
for (int i = 0; i < 3; i++)
|
||||
|
@ -12,11 +12,11 @@
|
||||
#include <consensus/validation.h>
|
||||
#include <core_io.h>
|
||||
#include <key.h>
|
||||
#include <keystore.h>
|
||||
#include <validation.h>
|
||||
#include <policy/policy.h>
|
||||
#include <policy/settings.h>
|
||||
#include <script/script.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <script/script_error.h>
|
||||
#include <streams.h>
|
||||
#include <util/strencodings.h>
|
||||
@ -262,7 +262,7 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
|
||||
// paid to a TX_PUBKEYHASH.
|
||||
//
|
||||
static std::vector<CMutableTransaction>
|
||||
SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
|
||||
SetupDummyInputs(FillableSigningProvider& keystoreRet, CCoinsViewCache& coinsRet)
|
||||
{
|
||||
std::vector<CMutableTransaction> dummyTransactions;
|
||||
dummyTransactions.resize(2);
|
||||
@ -295,7 +295,7 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_Get)
|
||||
{
|
||||
CBasicKeyStore keystore;
|
||||
FillableSigningProvider keystore;
|
||||
CCoinsView coinsDummy;
|
||||
CCoinsViewCache coins(&coinsDummy);
|
||||
std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
|
||||
@ -322,7 +322,7 @@ BOOST_AUTO_TEST_CASE(test_Get)
|
||||
BOOST_AUTO_TEST_CASE(test_IsStandard)
|
||||
{
|
||||
LOCK(cs_main);
|
||||
CBasicKeyStore keystore;
|
||||
FillableSigningProvider keystore;
|
||||
CCoinsView coinsDummy;
|
||||
CCoinsViewCache coins(&coinsDummy);
|
||||
std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
|
||||
|
@ -7,8 +7,8 @@
|
||||
#include <txmempool.h>
|
||||
#include <script/standard.h>
|
||||
#include <script/sign.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <keystore.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
@ -153,7 +153,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
|
||||
CScript p2sh_scriptPubKey = GetScriptForDestination(CScriptID(p2pk_scriptPubKey));
|
||||
CScript p2pkh_scriptPubKey = GetScriptForDestination(coinbaseKey.GetPubKey().GetID());
|
||||
|
||||
CBasicKeyStore keystore;
|
||||
FillableSigningProvider keystore;
|
||||
BOOST_CHECK(keystore.AddKey(coinbaseKey));
|
||||
BOOST_CHECK(keystore.AddCScript(p2pk_scriptPubKey));
|
||||
|
||||
|
@ -104,8 +104,7 @@ bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingM
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
|
||||
bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
|
||||
{
|
||||
CCrypter cKeyCrypter;
|
||||
std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
|
||||
@ -115,7 +114,6 @@ static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMateri
|
||||
return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
|
||||
}
|
||||
|
||||
|
||||
// General secure AES 256 CBC encryption routine
|
||||
bool EncryptAES256(const SecureString& sKey, const SecureString& sPlaintext, const std::string& sIV, std::string& sCiphertext)
|
||||
{
|
||||
@ -138,7 +136,7 @@ bool EncryptAES256(const SecureString& sKey, const SecureString& sPlaintext, con
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
|
||||
@ -171,7 +169,7 @@ bool DecryptAES256(const SecureString& sKey, const std::string& sCiphertext, con
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
if(!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
|
||||
@ -183,373 +181,3 @@ static bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsi
|
||||
key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
|
||||
return key.VerifyPubKey(vchPubKey);
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::SetCrypted()
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
if (fUseCrypto)
|
||||
return true;
|
||||
if (!mapKeys.empty())
|
||||
return false;
|
||||
fUseCrypto = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// This function should be used in a different combinations to determine
|
||||
// if CCryptoKeyStore is fully locked so that no operations requiring access
|
||||
// to private keys are possible:
|
||||
// IsLocked(true)
|
||||
// or if CCryptoKeyStore's private keys are available for mixing only:
|
||||
// !IsLocked(true) && IsLocked()
|
||||
// or if they are available for everything:
|
||||
// !IsLocked()
|
||||
bool CCryptoKeyStore::IsLocked(bool fForMixing) const
|
||||
{
|
||||
if (!IsCrypted())
|
||||
return false;
|
||||
bool result;
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
result = vMasterKey.empty();
|
||||
}
|
||||
// fForMixing fOnlyMixingAllowed return
|
||||
// ---------------------------------------
|
||||
// true true result
|
||||
// true false result
|
||||
// false true true
|
||||
// false false result
|
||||
|
||||
if(!fForMixing && fOnlyMixingAllowed) return true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::Lock(bool fAllowMixing)
|
||||
{
|
||||
if (!SetCrypted())
|
||||
return false;
|
||||
|
||||
if(!fAllowMixing) {
|
||||
LOCK(cs_KeyStore);
|
||||
vMasterKey.clear();
|
||||
}
|
||||
|
||||
fOnlyMixingAllowed = fAllowMixing;
|
||||
NotifyStatusChanged(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn, bool fForMixingOnly, 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 && cryptedHDChain.IsNull() && !accept_no_keys))
|
||||
return false;
|
||||
|
||||
vMasterKey = vMasterKeyIn;
|
||||
|
||||
if(!cryptedHDChain.IsNull()) {
|
||||
bool chainPass = false;
|
||||
// try to decrypt seed and make sure it matches
|
||||
CHDChain hdChainTmp;
|
||||
if (DecryptHDChain(hdChainTmp)) {
|
||||
// make sure seed matches this chain
|
||||
chainPass = cryptedHDChain.GetID() == hdChainTmp.GetSeedHash();
|
||||
}
|
||||
if (!chainPass) {
|
||||
vMasterKey.clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
fDecryptionThoroughlyChecked = true;
|
||||
}
|
||||
fOnlyMixingAllowed = fForMixingOnly;
|
||||
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(true)) {
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::EncryptHDChain(const CKeyingMaterial& vMasterKeyIn, const CHDChain& chain)
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
// should call EncryptKeys first
|
||||
if (!IsCrypted())
|
||||
return false;
|
||||
|
||||
if (!cryptedHDChain.IsNull())
|
||||
return true;
|
||||
|
||||
if (cryptedHDChain.IsCrypted())
|
||||
return true;
|
||||
|
||||
if (hdChain.IsNull() && !chain.IsNull()) {
|
||||
// Encrypting a new HDChain for an already encrypted non-HD wallet
|
||||
hdChain = chain;
|
||||
}
|
||||
|
||||
// make sure seed matches this chain
|
||||
if (hdChain.GetID() != hdChain.GetSeedHash())
|
||||
return false;
|
||||
|
||||
std::vector<unsigned char> vchCryptedSeed;
|
||||
if (!EncryptSecret(vMasterKeyIn, hdChain.GetSeed(), hdChain.GetID(), vchCryptedSeed))
|
||||
return false;
|
||||
|
||||
hdChain.Debug(__func__);
|
||||
cryptedHDChain = hdChain;
|
||||
cryptedHDChain.SetCrypted(true);
|
||||
|
||||
SecureVector vchSecureCryptedSeed(vchCryptedSeed.begin(), vchCryptedSeed.end());
|
||||
if (!cryptedHDChain.SetSeed(vchSecureCryptedSeed, false))
|
||||
return false;
|
||||
|
||||
SecureVector vchMnemonic;
|
||||
SecureVector vchMnemonicPassphrase;
|
||||
|
||||
// it's ok to have no mnemonic if wallet was initialized via hdseed
|
||||
if (hdChain.GetMnemonic(vchMnemonic, vchMnemonicPassphrase)) {
|
||||
std::vector<unsigned char> vchCryptedMnemonic;
|
||||
std::vector<unsigned char> vchCryptedMnemonicPassphrase;
|
||||
|
||||
if (!vchMnemonic.empty() && !EncryptSecret(vMasterKeyIn, vchMnemonic, hdChain.GetID(), vchCryptedMnemonic))
|
||||
return false;
|
||||
if (!vchMnemonicPassphrase.empty() && !EncryptSecret(vMasterKeyIn, vchMnemonicPassphrase, hdChain.GetID(), vchCryptedMnemonicPassphrase))
|
||||
return false;
|
||||
|
||||
SecureVector vchSecureCryptedMnemonic(vchCryptedMnemonic.begin(), vchCryptedMnemonic.end());
|
||||
SecureVector vchSecureCryptedMnemonicPassphrase(vchCryptedMnemonicPassphrase.begin(), vchCryptedMnemonicPassphrase.end());
|
||||
if (!cryptedHDChain.SetMnemonic(vchSecureCryptedMnemonic, vchSecureCryptedMnemonicPassphrase, false))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hdChain.SetNull())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::DecryptHDChain(CHDChain& hdChainRet) const
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
if (!IsCrypted())
|
||||
return true;
|
||||
|
||||
if (cryptedHDChain.IsNull())
|
||||
return false;
|
||||
|
||||
if (!cryptedHDChain.IsCrypted())
|
||||
return false;
|
||||
|
||||
SecureVector vchSecureSeed;
|
||||
SecureVector vchSecureCryptedSeed = cryptedHDChain.GetSeed();
|
||||
std::vector<unsigned char> vchCryptedSeed(vchSecureCryptedSeed.begin(), vchSecureCryptedSeed.end());
|
||||
if (!DecryptSecret(vMasterKey, vchCryptedSeed, cryptedHDChain.GetID(), vchSecureSeed))
|
||||
return false;
|
||||
|
||||
hdChainRet = cryptedHDChain;
|
||||
if (!hdChainRet.SetSeed(vchSecureSeed, false))
|
||||
return false;
|
||||
|
||||
// hash of decrypted seed must match chain id
|
||||
if (hdChainRet.GetSeedHash() != cryptedHDChain.GetID())
|
||||
return false;
|
||||
|
||||
SecureVector vchSecureCryptedMnemonic;
|
||||
SecureVector vchSecureCryptedMnemonicPassphrase;
|
||||
|
||||
// it's ok to have no mnemonic if wallet was initialized via hdseed
|
||||
if (cryptedHDChain.GetMnemonic(vchSecureCryptedMnemonic, vchSecureCryptedMnemonicPassphrase)) {
|
||||
SecureVector vchSecureMnemonic;
|
||||
SecureVector vchSecureMnemonicPassphrase;
|
||||
|
||||
std::vector<unsigned char> vchCryptedMnemonic(vchSecureCryptedMnemonic.begin(), vchSecureCryptedMnemonic.end());
|
||||
std::vector<unsigned char> vchCryptedMnemonicPassphrase(vchSecureCryptedMnemonicPassphrase.begin(), vchSecureCryptedMnemonicPassphrase.end());
|
||||
|
||||
if (!vchCryptedMnemonic.empty() && !DecryptSecret(vMasterKey, vchCryptedMnemonic, cryptedHDChain.GetID(), vchSecureMnemonic))
|
||||
return false;
|
||||
if (!vchCryptedMnemonicPassphrase.empty() && !DecryptSecret(vMasterKey, vchCryptedMnemonicPassphrase, cryptedHDChain.GetID(), vchSecureMnemonicPassphrase))
|
||||
return false;
|
||||
|
||||
if (!hdChainRet.SetMnemonic(vchSecureMnemonic, vchSecureMnemonicPassphrase, false))
|
||||
return false;
|
||||
}
|
||||
|
||||
hdChainRet.SetCrypted(false);
|
||||
hdChainRet.Debug(__func__);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::SetHDChain(const CHDChain& chain)
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
if (IsCrypted())
|
||||
return false;
|
||||
|
||||
if (chain.IsCrypted())
|
||||
return false;
|
||||
|
||||
hdChain = chain;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::SetCryptedHDChain(const CHDChain& chain)
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
if (!SetCrypted())
|
||||
return false;
|
||||
|
||||
if (!chain.IsCrypted())
|
||||
return false;
|
||||
|
||||
cryptedHDChain = chain;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::GetHDChain(CHDChain& hdChainRet) const
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
if(IsCrypted()) {
|
||||
hdChainRet = cryptedHDChain;
|
||||
return !cryptedHDChain.IsNull();
|
||||
}
|
||||
|
||||
hdChainRet = hdChain;
|
||||
return !hdChain.IsNull();
|
||||
}
|
||||
|
@ -5,9 +5,9 @@
|
||||
#ifndef BITCOIN_WALLET_CRYPTER_H
|
||||
#define BITCOIN_WALLET_CRYPTER_H
|
||||
|
||||
#include <keystore.h>
|
||||
#include <serialize.h>
|
||||
#include <support/allocators/secure.h>
|
||||
#include <script/signingprovider.h>
|
||||
|
||||
|
||||
const unsigned int WALLET_CRYPTO_KEY_SIZE = 32;
|
||||
@ -106,65 +106,8 @@ bool EncryptAES256(const SecureString& sKey, const SecureString& sPlaintext, con
|
||||
bool DecryptAES256(const SecureString& sKey, const std::string& sCiphertext, const std::string& sIV, SecureString& sPlaintext);
|
||||
|
||||
|
||||
/** Keystore which keeps the private keys encrypted.
|
||||
* It derives from the basic key store, which is used if no encryption is active.
|
||||
*/
|
||||
class CCryptoKeyStore : public CBasicKeyStore
|
||||
{
|
||||
private:
|
||||
CHDChain cryptedHDChain GUARDED_BY(cs_KeyStore);
|
||||
|
||||
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;
|
||||
|
||||
//! if fOnlyMixingAllowed is true, only mixing should be allowed in unlocked wallet
|
||||
bool fOnlyMixingAllowed;
|
||||
|
||||
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 EncryptHDChain(const CKeyingMaterial& vMasterKeyIn, const CHDChain& chain = CHDChain());
|
||||
bool DecryptHDChain(CHDChain& hdChainRet) const;
|
||||
bool SetHDChain(const CHDChain& chain);
|
||||
bool SetCryptedHDChain(const CHDChain& chain);
|
||||
|
||||
bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool fForMixingOnly = false, bool accept_no_keys = false);
|
||||
CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore);
|
||||
|
||||
public:
|
||||
CCryptoKeyStore() : fUseCrypto(false), fDecryptionThoroughlyChecked(false), fOnlyMixingAllowed(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool IsCrypted() const { return fUseCrypto; }
|
||||
bool IsLocked(bool fForMixing = false) const;
|
||||
bool Lock(bool fForMixing = false);
|
||||
|
||||
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;
|
||||
|
||||
virtual bool GetHDChain(CHDChain& hdChainRet) const override;
|
||||
|
||||
/**
|
||||
* Wallet status (encrypted, locked) changed.
|
||||
* Note: Called without locks held.
|
||||
*/
|
||||
boost::signals2::signal<void (CCryptoKeyStore* wallet)> NotifyStatusChanged;
|
||||
};
|
||||
bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext);
|
||||
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);
|
||||
|
||||
#endif // BITCOIN_WALLET_CRYPTER_H
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <key.h>
|
||||
#include <script/script.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <wallet/wallet.h>
|
||||
|
||||
typedef std::vector<unsigned char> valtype;
|
||||
|
@ -61,6 +61,16 @@ static inline bool GetAvoidReuseFlag(CWallet * const pwallet, const UniValue& pa
|
||||
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)
|
||||
{
|
||||
if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include <interfaces/wallet.h>
|
||||
#include <key.h>
|
||||
#include <key_io.h>
|
||||
#include <keystore.h>
|
||||
#include <policy/fees.h>
|
||||
#include <policy/policy.h>
|
||||
#include <policy/settings.h>
|
||||
@ -25,6 +24,7 @@
|
||||
#include <script/descriptor.h>
|
||||
#include <script/script.h>
|
||||
#include <script/sign.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <txmempool.h>
|
||||
#include <util/bip32.h>
|
||||
#include <util/error.h>
|
||||
@ -475,7 +475,7 @@ bool CWallet::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return CCryptoKeyStore::GetPubKey(address, vchPubKeyOut);
|
||||
return GetPubKeyInner(address, vchPubKeyOut);
|
||||
}
|
||||
|
||||
bool CWallet::GetKey(const CKeyID &address, CKey& keyOut) const
|
||||
@ -503,16 +503,25 @@ bool CWallet::GetKey(const CKeyID &address, CKey& keyOut) const
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return CCryptoKeyStore::GetKey(address, keyOut);
|
||||
return GetKeyInner(address, keyOut);
|
||||
}
|
||||
}
|
||||
|
||||
bool CWallet::HaveKeyInner(const CKeyID &address) const
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
if (!IsCrypted()) {
|
||||
return FillableSigningProvider::HaveKey(address);
|
||||
}
|
||||
return mapCryptedKeys.count(address) > 0;
|
||||
}
|
||||
|
||||
bool CWallet::HaveKey(const CKeyID &address) const
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
if (mapHdPubKeys.count(address) > 0)
|
||||
return true;
|
||||
return CCryptoKeyStore::HaveKey(address);
|
||||
return HaveKeyInner(address);
|
||||
}
|
||||
|
||||
bool CWallet::LoadHDPubKey(const CHDPubKey &hdPubKey)
|
||||
@ -559,14 +568,14 @@ bool CWallet::AddKeyPubKeyWithDB(WalletBatch& batch, const CKey& secret, const C
|
||||
// Make sure we aren't adding private keys to private key disabled wallets
|
||||
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
|
||||
// tunneled through to it.
|
||||
bool needsDB = !encrypted_batch;
|
||||
if (needsDB) {
|
||||
encrypted_batch = &batch;
|
||||
}
|
||||
if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey)) {
|
||||
if (!AddKeyPubKeyInner(secret, pubkey)) {
|
||||
if (needsDB) encrypted_batch = nullptr;
|
||||
return false;
|
||||
}
|
||||
@ -602,7 +611,7 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
|
||||
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
|
||||
const std::vector<unsigned char> &vchCryptedSecret)
|
||||
{
|
||||
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
|
||||
if (!AddCryptedKeyInner(vchPubKey, vchCryptedSecret))
|
||||
return false;
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
@ -690,7 +699,7 @@ void CWallet::UpgradeKeyMetadata()
|
||||
|
||||
bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
|
||||
{
|
||||
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
|
||||
return AddCryptedKeyInner(vchPubKey, vchCryptedSecret);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -723,7 +732,7 @@ bool CWallet::AddCScript(const CScript& redeemScript)
|
||||
|
||||
bool CWallet::AddCScriptWithDB(WalletBatch& batch, const CScript& redeemScript)
|
||||
{
|
||||
if (!CCryptoKeyStore::AddCScript(redeemScript))
|
||||
if (!FillableSigningProvider::AddCScript(redeemScript))
|
||||
return false;
|
||||
if (batch.WriteCScript(Hash160(redeemScript), redeemScript)) {
|
||||
UnsetWalletFlag(batch, WALLET_FLAG_BLANK_WALLET);
|
||||
@ -744,12 +753,30 @@ bool CWallet::LoadCScript(const CScript& redeemScript)
|
||||
return true;
|
||||
}
|
||||
|
||||
return CCryptoKeyStore::AddCScript(redeemScript);
|
||||
return FillableSigningProvider::AddCScript(redeemScript);
|
||||
}
|
||||
|
||||
static bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut)
|
||||
{
|
||||
std::vector<std::vector<unsigned char>> solutions;
|
||||
return Solver(dest, solutions) == TX_PUBKEY &&
|
||||
(pubKeyOut = CPubKey(solutions[0])).IsFullyValid();
|
||||
}
|
||||
|
||||
bool CWallet::AddWatchOnlyInMem(const CScript &dest)
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
setWatchOnly.insert(dest);
|
||||
CPubKey pubKey;
|
||||
if (ExtractPubKey(dest, pubKey)) {
|
||||
mapWatchKeys[pubKey.GetID()] = pubKey;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWallet::AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest)
|
||||
{
|
||||
if (!CCryptoKeyStore::AddWatchOnly(dest))
|
||||
if (!AddWatchOnlyInMem(dest))
|
||||
return false;
|
||||
const CKeyMetadata& meta = m_script_metadata[CScriptID(dest)];
|
||||
UpdateTimeFirstKey(meta.nCreateTime);
|
||||
@ -782,8 +809,15 @@ bool CWallet::AddWatchOnly(const CScript& dest, int64_t nCreateTime)
|
||||
bool CWallet::RemoveWatchOnly(const CScript &dest)
|
||||
{
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
if (!HaveWatchOnly())
|
||||
NotifyWatchonlyChanged(false);
|
||||
if (!WalletBatch(*database).EraseWatchOnly(dest))
|
||||
@ -794,7 +828,19 @@ bool CWallet::RemoveWatchOnly(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 fForMixingOnly, bool accept_no_keys)
|
||||
@ -813,7 +859,7 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool fForMixingOnl
|
||||
return false;
|
||||
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
|
||||
continue; // try another master key
|
||||
if (CCryptoKeyStore::Unlock(_vMasterKey, fForMixingOnly, accept_no_keys)) {
|
||||
if (Unlock(_vMasterKey, fForMixingOnly, accept_no_keys)) {
|
||||
// Now that we've unlocked, upgrade the key metadata
|
||||
UpgradeKeyMetadata();
|
||||
if(nWalletBackups == -2) {
|
||||
@ -844,7 +890,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
|
||||
return false;
|
||||
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
|
||||
return false;
|
||||
if (CCryptoKeyStore::Unlock(_vMasterKey))
|
||||
if (Unlock(_vMasterKey))
|
||||
{
|
||||
int64_t nStartTime = GetTimeMillis();
|
||||
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
|
||||
@ -2028,7 +2074,7 @@ bool CWallet::SetHDChain(WalletBatch &batch, const CHDChain& chain, bool memonly
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
|
||||
if (!CCryptoKeyStore::SetHDChain(chain))
|
||||
if (!SetHDChain(chain))
|
||||
return false;
|
||||
|
||||
if (!memonly) {
|
||||
@ -2046,7 +2092,7 @@ bool CWallet::SetCryptedHDChain(WalletBatch &batch, const CHDChain& chain, bool
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
|
||||
if (!CCryptoKeyStore::SetCryptedHDChain(chain))
|
||||
if (!SetCryptedHDChain(chain))
|
||||
return false;
|
||||
|
||||
if (!memonly) {
|
||||
@ -5771,3 +5817,378 @@ bool CWallet::AddKeyOrigin(const CPubKey& pubkey, const KeyOriginInfo& info)
|
||||
mapKeyMetadata[pubkey.GetID()].has_key_origin = true;
|
||||
return 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;
|
||||
}
|
||||
|
||||
// This function should be used in a different combinations to determine
|
||||
// if FillableSigningProvider is fully locked so that no operations requiring access
|
||||
// to private keys are possible:
|
||||
// IsLocked(true)
|
||||
// or if FillableSigningProvider's private keys are available for mixing only:
|
||||
// !IsLocked(true) && IsLocked()
|
||||
// or if they are available for everything:
|
||||
// !IsLocked()
|
||||
bool CWallet::IsLocked(bool fForMixing) const
|
||||
{
|
||||
if (!IsCrypted())
|
||||
return false;
|
||||
bool result;
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
result = vMasterKey.empty();
|
||||
}
|
||||
// fForMixing fOnlyMixingAllowed return
|
||||
// ---------------------------------------
|
||||
// true true result
|
||||
// true false result
|
||||
// false true true
|
||||
// false false result
|
||||
|
||||
if(!fForMixing && fOnlyMixingAllowed) return true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CWallet::Lock(bool fAllowMixing)
|
||||
{
|
||||
if (!SetCrypted())
|
||||
return false;
|
||||
|
||||
if(!fAllowMixing) {
|
||||
LOCK(cs_KeyStore);
|
||||
vMasterKey.clear();
|
||||
}
|
||||
|
||||
fOnlyMixingAllowed = fAllowMixing;
|
||||
NotifyStatusChanged(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWallet::Unlock(const CKeyingMaterial& vMasterKeyIn, bool fForMixingOnly, 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 && cryptedHDChain.IsNull() && !accept_no_keys))
|
||||
return false;
|
||||
|
||||
vMasterKey = vMasterKeyIn;
|
||||
|
||||
if(!cryptedHDChain.IsNull()) {
|
||||
bool chainPass = false;
|
||||
// try to decrypt seed and make sure it matches
|
||||
CHDChain hdChainTmp;
|
||||
if (DecryptHDChain(hdChainTmp)) {
|
||||
// make sure seed matches this chain
|
||||
chainPass = cryptedHDChain.GetID() == hdChainTmp.GetSeedHash();
|
||||
}
|
||||
if (!chainPass) {
|
||||
vMasterKey.clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
fDecryptionThoroughlyChecked = true;
|
||||
}
|
||||
fOnlyMixingAllowed = fForMixingOnly;
|
||||
NotifyStatusChanged(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWallet::AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey)
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
if (!IsCrypted()) {
|
||||
return FillableSigningProvider::AddKeyPubKey(key, pubkey);
|
||||
}
|
||||
|
||||
if (IsLocked(true)) {
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWallet::GetKeyInner(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::GetPubKeyInner(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::EncryptHDChain(const CKeyingMaterial& vMasterKeyIn, const CHDChain& chain)
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
// should call EncryptKeys first
|
||||
if (!IsCrypted())
|
||||
return false;
|
||||
|
||||
if (!cryptedHDChain.IsNull())
|
||||
return true;
|
||||
|
||||
if (cryptedHDChain.IsCrypted())
|
||||
return true;
|
||||
|
||||
if (hdChain.IsNull() && !chain.IsNull()) {
|
||||
// Encrypting a new HDChain for an already encrypted non-HD wallet
|
||||
hdChain = chain;
|
||||
}
|
||||
|
||||
// make sure seed matches this chain
|
||||
if (hdChain.GetID() != hdChain.GetSeedHash())
|
||||
return false;
|
||||
|
||||
std::vector<unsigned char> vchCryptedSeed;
|
||||
if (!EncryptSecret(vMasterKeyIn, hdChain.GetSeed(), hdChain.GetID(), vchCryptedSeed))
|
||||
return false;
|
||||
|
||||
hdChain.Debug(__func__);
|
||||
cryptedHDChain = hdChain;
|
||||
cryptedHDChain.SetCrypted(true);
|
||||
|
||||
SecureVector vchSecureCryptedSeed(vchCryptedSeed.begin(), vchCryptedSeed.end());
|
||||
if (!cryptedHDChain.SetSeed(vchSecureCryptedSeed, false))
|
||||
return false;
|
||||
|
||||
SecureVector vchMnemonic;
|
||||
SecureVector vchMnemonicPassphrase;
|
||||
|
||||
// it's ok to have no mnemonic if wallet was initialized via hdseed
|
||||
if (hdChain.GetMnemonic(vchMnemonic, vchMnemonicPassphrase)) {
|
||||
std::vector<unsigned char> vchCryptedMnemonic;
|
||||
std::vector<unsigned char> vchCryptedMnemonicPassphrase;
|
||||
|
||||
if (!vchMnemonic.empty() && !EncryptSecret(vMasterKeyIn, vchMnemonic, hdChain.GetID(), vchCryptedMnemonic))
|
||||
return false;
|
||||
if (!vchMnemonicPassphrase.empty() && !EncryptSecret(vMasterKeyIn, vchMnemonicPassphrase, hdChain.GetID(), vchCryptedMnemonicPassphrase))
|
||||
return false;
|
||||
|
||||
SecureVector vchSecureCryptedMnemonic(vchCryptedMnemonic.begin(), vchCryptedMnemonic.end());
|
||||
SecureVector vchSecureCryptedMnemonicPassphrase(vchCryptedMnemonicPassphrase.begin(), vchCryptedMnemonicPassphrase.end());
|
||||
if (!cryptedHDChain.SetMnemonic(vchSecureCryptedMnemonic, vchSecureCryptedMnemonicPassphrase, false))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hdChain.SetNull())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWallet::DecryptHDChain(CHDChain& hdChainRet) const
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
if (!IsCrypted())
|
||||
return true;
|
||||
|
||||
if (cryptedHDChain.IsNull())
|
||||
return false;
|
||||
|
||||
if (!cryptedHDChain.IsCrypted())
|
||||
return false;
|
||||
|
||||
SecureVector vchSecureSeed;
|
||||
SecureVector vchSecureCryptedSeed = cryptedHDChain.GetSeed();
|
||||
std::vector<unsigned char> vchCryptedSeed(vchSecureCryptedSeed.begin(), vchSecureCryptedSeed.end());
|
||||
if (!DecryptSecret(vMasterKey, vchCryptedSeed, cryptedHDChain.GetID(), vchSecureSeed))
|
||||
return false;
|
||||
|
||||
hdChainRet = cryptedHDChain;
|
||||
if (!hdChainRet.SetSeed(vchSecureSeed, false))
|
||||
return false;
|
||||
|
||||
// hash of decrypted seed must match chain id
|
||||
if (hdChainRet.GetSeedHash() != cryptedHDChain.GetID())
|
||||
return false;
|
||||
|
||||
SecureVector vchSecureCryptedMnemonic;
|
||||
SecureVector vchSecureCryptedMnemonicPassphrase;
|
||||
|
||||
// it's ok to have no mnemonic if wallet was initialized via hdseed
|
||||
if (cryptedHDChain.GetMnemonic(vchSecureCryptedMnemonic, vchSecureCryptedMnemonicPassphrase)) {
|
||||
SecureVector vchSecureMnemonic;
|
||||
SecureVector vchSecureMnemonicPassphrase;
|
||||
|
||||
std::vector<unsigned char> vchCryptedMnemonic(vchSecureCryptedMnemonic.begin(), vchSecureCryptedMnemonic.end());
|
||||
std::vector<unsigned char> vchCryptedMnemonicPassphrase(vchSecureCryptedMnemonicPassphrase.begin(), vchSecureCryptedMnemonicPassphrase.end());
|
||||
|
||||
if (!vchCryptedMnemonic.empty() && !DecryptSecret(vMasterKey, vchCryptedMnemonic, cryptedHDChain.GetID(), vchSecureMnemonic))
|
||||
return false;
|
||||
if (!vchCryptedMnemonicPassphrase.empty() && !DecryptSecret(vMasterKey, vchCryptedMnemonicPassphrase, cryptedHDChain.GetID(), vchSecureMnemonicPassphrase))
|
||||
return false;
|
||||
|
||||
if (!hdChainRet.SetMnemonic(vchSecureMnemonic, vchSecureMnemonicPassphrase, false))
|
||||
return false;
|
||||
}
|
||||
|
||||
hdChainRet.SetCrypted(false);
|
||||
hdChainRet.Debug(__func__);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWallet::SetHDChain(const CHDChain& chain)
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
if (IsCrypted())
|
||||
return false;
|
||||
|
||||
if (chain.IsCrypted())
|
||||
return false;
|
||||
|
||||
hdChain = chain;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWallet::SetCryptedHDChain(const CHDChain& chain)
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
if (!SetCrypted())
|
||||
return false;
|
||||
|
||||
if (!chain.IsCrypted())
|
||||
return false;
|
||||
|
||||
cryptedHDChain = chain;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWallet::GetHDChain(CHDChain& hdChainRet) const
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
if(IsCrypted()) {
|
||||
hdChainRet = cryptedHDChain;
|
||||
return !cryptedHDChain.IsNull();
|
||||
}
|
||||
|
||||
hdChainRet = hdChain;
|
||||
return !hdChain.IsNull();
|
||||
}
|
||||
|
@ -38,6 +38,8 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/signals2/signal.hpp>
|
||||
|
||||
struct bilingual_str;
|
||||
|
||||
using LoadWalletFn = std::function<void(std::unique_ptr<interfaces::Wallet> wallet)>;
|
||||
@ -764,9 +766,48 @@ class WalletRescanReserver; //forward declarations for ScanForWalletTransactions
|
||||
* 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.
|
||||
*/
|
||||
class CWallet final : public CCryptoKeyStore, public interfaces::Chain::Notifications
|
||||
class CWallet final : public FillableSigningProvider, public interfaces::Chain::Notifications
|
||||
{
|
||||
private:
|
||||
CHDChain cryptedHDChain GUARDED_BY(cs_KeyStore);
|
||||
|
||||
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;
|
||||
|
||||
//! if fOnlyMixingAllowed is true, only mixing should be allowed in unlocked wallet
|
||||
bool fOnlyMixingAllowed;
|
||||
|
||||
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 EncryptHDChain(const CKeyingMaterial& vMasterKeyIn, const CHDChain& chain = CHDChain());
|
||||
bool DecryptHDChain(CHDChain& hdChainRet) const;
|
||||
bool SetHDChain(const CHDChain& chain);
|
||||
bool SetCryptedHDChain(const CHDChain& chain);
|
||||
|
||||
bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool fForMixingOnly = false, bool accept_no_keys = false);
|
||||
CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore);
|
||||
WatchOnlySet setWatchOnly GUARDED_BY(cs_KeyStore);
|
||||
WatchKeyMap mapWatchKeys GUARDED_BY(cs_KeyStore);
|
||||
|
||||
bool HaveKeyInner(const CKeyID &address) const;
|
||||
bool AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
|
||||
bool AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey);
|
||||
bool GetKeyInner(const CKeyID &address, CKey& keyOut) const;
|
||||
bool GetPubKeyInner(const CKeyID &address, CPubKey& vchPubKeyOut) const;
|
||||
|
||||
std::atomic<bool> fAbortRescan{false};
|
||||
std::atomic<bool> fScanningWallet{false}; // controlled by WalletRescanReserver
|
||||
std::atomic<int64_t> m_scanning_start{0};
|
||||
@ -852,7 +893,8 @@ private:
|
||||
* of the other AddWatchOnly which accepts a timestamp and sets
|
||||
* 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 AddWatchOnlyInMem(const CScript &dest);
|
||||
|
||||
/** Interface for accessing chain state. */
|
||||
interfaces::Chain* m_chain;
|
||||
@ -941,7 +983,10 @@ public:
|
||||
|
||||
/** Construct wallet with specified name and database implementation. */
|
||||
CWallet(interfaces::Chain* chain, const WalletLocation& location, std::unique_ptr<WalletDatabase> database)
|
||||
: m_chain(chain),
|
||||
: fUseCrypto(false),
|
||||
fDecryptionThoroughlyChecked(false),
|
||||
fOnlyMixingAllowed(false),
|
||||
m_chain(chain),
|
||||
m_location(location),
|
||||
database(std::move(database))
|
||||
{
|
||||
@ -957,6 +1002,9 @@ public:
|
||||
|
||||
/** Interface to assert chain access */
|
||||
bool HaveChain() const { return m_chain ? true : false; }
|
||||
bool IsCrypted() const { return fUseCrypto; }
|
||||
bool IsLocked(bool fForMixing = false) const;
|
||||
bool Lock(bool fForMixing = false);
|
||||
|
||||
std::map<uint256, CWalletTx> mapWallet GUARDED_BY(cs_wallet);
|
||||
|
||||
@ -1068,7 +1116,7 @@ public:
|
||||
//! 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);
|
||||
//! 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)
|
||||
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);
|
||||
@ -1080,9 +1128,11 @@ public:
|
||||
int64_t GetTimeFirstKey() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
||||
//! 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)
|
||||
bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
|
||||
std::set<CKeyID> GetKeys() const override;
|
||||
virtual bool GetHDChain(CHDChain& hdChainRet) const override;
|
||||
bool AddCScript(const CScript& redeemScript) override;
|
||||
bool LoadCScript(const CScript& redeemScript);
|
||||
|
||||
@ -1100,9 +1150,15 @@ public:
|
||||
//! 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 AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest) 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)
|
||||
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;
|
||||
|
||||
//! Adds a key to the store, and saves it to disk.
|
||||
bool AddKeyPubKeyWithDB(WalletBatch &batch,const CKey& key, const CPubKey &pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
@ -1357,6 +1413,12 @@ public:
|
||||
/** ChainLock received */
|
||||
boost::signals2::signal<void (int height)> NotifyChainLockReceived;
|
||||
|
||||
/**
|
||||
* Wallet status (encrypted, locked) changed.
|
||||
* Note: Called without locks held.
|
||||
*/
|
||||
boost::signals2::signal<void (CWallet* wallet)> NotifyStatusChanged;
|
||||
|
||||
/** Inquire whether this wallet broadcasts transactions. */
|
||||
bool GetBroadcastTransactions() const { return fBroadcastTransactions; }
|
||||
/** Set whether this wallet broadcasts transactions. */
|
||||
|
@ -41,6 +41,7 @@ EXPECTED_CIRCULAR_DEPENDENCIES=(
|
||||
"governance/governance -> net_processing -> governance/governance"
|
||||
"governance/object -> governance/validators -> governance/object"
|
||||
"hdchain -> wallet/walletdb -> hdchain"
|
||||
"hdchain -> wallet/walletdb -> script/sign -> script/signingprovider -> hdchain"
|
||||
"llmq/quorums -> llmq/utils -> llmq/quorums"
|
||||
"llmq/blockprocessor -> net_processing -> llmq/blockprocessor"
|
||||
"llmq/chainlocks -> llmq/instantsend -> llmq/chainlocks"
|
||||
|
Loading…
Reference in New Issue
Block a user