mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-20 13:37:28 +02:00
Merge 6a97e8a060 into merged_master (Bitcoin PR #17260) (multiple commits)
This is the start of some nontrivial wallet refactoring by achow. See https://github.com/bitcoin-core/bitcoin-devwiki/wiki/Wallet-Class-Structure-Changes for a high-level design. This PR moves some stuff out of CWallet into a dummy "box" LegacyScriptPubKeyMan which is (currently) very tightly coulped to CWallet. Because of the coupling there are currently null-checks that cannot fail, things which assume non-nullness which will eventually be wrong, and a plethora of currently-equivalent ways to get from a CWallet to a provider or back. Our approach is basically to ignore the refactoring; leave the blinding key stuff in CWallet and have it call into the wallet's provider when we are obtaining the underlying keys. Later, probably in a post-rebase PR, we should rethink how we manage blinding keys to more closely match Core's "all keys go into providers" model.
This commit is contained in:
commit
e910b15aa8
24 changed files with 2218 additions and 1806 deletions
|
|
@ -247,6 +247,7 @@ BITCOIN_CORE_H = \
|
|||
wallet/load.h \
|
||||
wallet/psbtwallet.h \
|
||||
wallet/rpcwallet.h \
|
||||
wallet/scriptpubkeyman.h \
|
||||
wallet/wallet.h \
|
||||
wallet/walletdb.h \
|
||||
wallet/wallettool.h \
|
||||
|
|
@ -356,11 +357,11 @@ libbitcoin_wallet_a_SOURCES = \
|
|||
wallet/db.cpp \
|
||||
wallet/feebumper.cpp \
|
||||
wallet/fees.cpp \
|
||||
wallet/ismine.cpp \
|
||||
wallet/load.cpp \
|
||||
wallet/psbtwallet.cpp \
|
||||
wallet/rpcdump.cpp \
|
||||
wallet/rpcwallet.cpp \
|
||||
wallet/scriptpubkeyman.cpp \
|
||||
wallet/wallet.cpp \
|
||||
wallet/walletdb.cpp \
|
||||
wallet/walletutil.cpp \
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ WalletTx MakeWalletTx(interfaces::Chain::Lock& locked_chain, CWallet& wallet, co
|
|||
result.txout_is_mine.emplace_back(wallet.IsMine(txout));
|
||||
result.txout_address.emplace_back();
|
||||
result.txout_address_is_mine.emplace_back(ExtractDestination(txout.scriptPubKey, result.txout_address.back()) ?
|
||||
IsMine(wallet, result.txout_address.back()) :
|
||||
wallet.IsMine(result.txout_address.back()) :
|
||||
ISMINE_NO);
|
||||
result.txout_is_change.push_back(wallet.IsChange(txout));
|
||||
}
|
||||
|
|
@ -129,10 +129,17 @@ public:
|
|||
std::string error;
|
||||
return m_wallet->GetNewDestination(type, label, dest, error, add_blinding_key);
|
||||
}
|
||||
bool getPubKey(const CKeyID& address, CPubKey& pub_key) override { return m_wallet->GetPubKey(address, pub_key); }
|
||||
bool getPrivKey(const CKeyID& address, CKey& key) override { return m_wallet->GetKey(address, key); }
|
||||
bool isSpendable(const CTxDestination& dest) override { return IsMine(*m_wallet, dest) & ISMINE_SPENDABLE; }
|
||||
bool haveWatchOnly() override { return m_wallet->HaveWatchOnly(); };
|
||||
bool getPubKey(const CKeyID& address, CPubKey& pub_key) override { return m_wallet->GetLegacyScriptPubKeyMan()->GetPubKey(address, pub_key); }
|
||||
bool getPrivKey(const CKeyID& address, CKey& key) override { return m_wallet->GetLegacyScriptPubKeyMan()->GetKey(address, key); }
|
||||
bool isSpendable(const CTxDestination& dest) override { return m_wallet->IsMine(dest) & ISMINE_SPENDABLE; }
|
||||
bool haveWatchOnly() override
|
||||
{
|
||||
auto spk_man = m_wallet->GetLegacyScriptPubKeyMan();
|
||||
if (spk_man) {
|
||||
return spk_man->HaveWatchOnly();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
bool setAddressBook(const CTxDestination& dest, const std::string& name, const std::string& purpose) override
|
||||
{
|
||||
return m_wallet->SetAddressBook(dest, name, purpose);
|
||||
|
|
@ -155,7 +162,7 @@ public:
|
|||
*name = it->second.name;
|
||||
}
|
||||
if (is_mine) {
|
||||
*is_mine = IsMine(*m_wallet, dest);
|
||||
*is_mine = m_wallet->IsMine(dest);
|
||||
}
|
||||
if (purpose) {
|
||||
*purpose = it->second.purpose;
|
||||
|
|
@ -167,11 +174,11 @@ public:
|
|||
LOCK(m_wallet->cs_wallet);
|
||||
std::vector<WalletAddress> result;
|
||||
for (const auto& item : m_wallet->mapAddressBook) {
|
||||
result.emplace_back(item.first, IsMine(*m_wallet, item.first), item.second.name, item.second.purpose);
|
||||
result.emplace_back(item.first, m_wallet->IsMine(item.first), item.second.name, item.second.purpose);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
void learnRelatedScripts(const CPubKey& key, OutputType type) override { m_wallet->LearnRelatedScripts(key, type); }
|
||||
void learnRelatedScripts(const CPubKey& key, OutputType type) override { m_wallet->GetLegacyScriptPubKeyMan()->LearnRelatedScripts(key, type); }
|
||||
bool addDestData(const CTxDestination& dest, const std::string& key, const std::string& value) override
|
||||
{
|
||||
LOCK(m_wallet->cs_wallet);
|
||||
|
|
@ -357,7 +364,7 @@ public:
|
|||
result.balance = bal.m_mine_trusted;
|
||||
result.unconfirmed_balance = bal.m_mine_untrusted_pending;
|
||||
result.immature_balance = bal.m_mine_immature;
|
||||
result.have_watch_only = m_wallet->HaveWatchOnly();
|
||||
result.have_watch_only = haveWatchOnly();
|
||||
if (result.have_watch_only) {
|
||||
result.watch_only_balance = bal.m_watchonly_trusted;
|
||||
result.unconfirmed_watch_only_balance = bal.m_watchonly_untrusted_pending;
|
||||
|
|
|
|||
|
|
@ -139,9 +139,11 @@ void TestGUI()
|
|||
bool firstRun;
|
||||
wallet->LoadWallet(firstRun);
|
||||
{
|
||||
auto spk_man = wallet->GetLegacyScriptPubKeyMan();
|
||||
LOCK(wallet->cs_wallet);
|
||||
AssertLockHeld(spk_man->cs_wallet);
|
||||
wallet->SetAddressBook(GetDestinationForKey(test.coinbaseKey.GetPubKey(), wallet->m_default_address_type), "", "receive");
|
||||
wallet->AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
|
||||
spk_man->AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
|
||||
}
|
||||
{
|
||||
auto locked_chain = wallet->chain().lock();
|
||||
|
|
|
|||
|
|
@ -63,8 +63,6 @@ FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvide
|
|||
class FillableSigningProvider : public SigningProvider
|
||||
{
|
||||
protected:
|
||||
mutable CCriticalSection cs_KeyStore;
|
||||
|
||||
using KeyMap = std::map<CKeyID, CKey>;
|
||||
using ScriptMap = std::map<CScriptID, CScript>;
|
||||
|
||||
|
|
@ -74,6 +72,8 @@ protected:
|
|||
void ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
|
||||
|
||||
public:
|
||||
mutable CCriticalSection cs_KeyStore;
|
||||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -32,13 +32,15 @@ std::string getnewaddress(CWallet& w)
|
|||
|
||||
void importaddress(CWallet& wallet, const std::string& address)
|
||||
{
|
||||
auto spk_man = wallet.GetLegacyScriptPubKeyMan();
|
||||
LOCK(wallet.cs_wallet);
|
||||
AssertLockHeld(spk_man->cs_wallet);
|
||||
const auto dest = DecodeDestination(address);
|
||||
assert(IsValidDestination(dest));
|
||||
const auto script = GetScriptForDestination(dest);
|
||||
wallet.MarkDirty();
|
||||
assert(!wallet.HaveWatchOnly(script));
|
||||
if (!wallet.AddWatchOnly(script, 0 /* nCreateTime */)) assert(false);
|
||||
assert(!spk_man->HaveWatchOnly(script));
|
||||
if (!spk_man->AddWatchOnly(script, 0 /* nCreateTime */)) assert(false);
|
||||
wallet.SetAddressBook(dest, /* label */ "", "receive");
|
||||
}
|
||||
#endif // ENABLE_WALLET
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
#define BITCOIN_UTIL_TRANSLATION_H
|
||||
|
||||
#include <tinyformat.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
/**
|
||||
* Bilingual messages:
|
||||
|
|
|
|||
|
|
@ -1,199 +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.
|
||||
|
||||
#include <wallet/ismine.h>
|
||||
|
||||
#include <key.h>
|
||||
#include <script/script.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <wallet/wallet.h>
|
||||
|
||||
#include <chainparams.h>
|
||||
|
||||
typedef std::vector<unsigned char> valtype;
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* This is an enum that tracks the execution context of a script, similar to
|
||||
* SigVersion in script/interpreter. It is separate however because we want to
|
||||
* distinguish between top-level scriptPubKey execution and P2SH redeemScript
|
||||
* execution (a distinction that has no impact on consensus rules).
|
||||
*/
|
||||
enum class IsMineSigVersion
|
||||
{
|
||||
TOP = 0, //!< scriptPubKey execution
|
||||
P2SH = 1, //!< P2SH redeemScript
|
||||
WITNESS_V0 = 2, //!< P2WSH witness script execution
|
||||
};
|
||||
|
||||
/**
|
||||
* This is an internal representation of isminetype + invalidity.
|
||||
* Its order is significant, as we return the max of all explored
|
||||
* possibilities.
|
||||
*/
|
||||
enum class IsMineResult
|
||||
{
|
||||
NO = 0, //!< Not ours
|
||||
WATCH_ONLY = 1, //!< Included in watch-only balance
|
||||
SPENDABLE = 2, //!< Included in all balances
|
||||
INVALID = 3, //!< Not spendable by anyone (uncompressed pubkey in segwit, P2SH inside P2SH or witness, witness inside witness)
|
||||
};
|
||||
|
||||
bool PermitsUncompressed(IsMineSigVersion sigversion)
|
||||
{
|
||||
return sigversion == IsMineSigVersion::TOP || sigversion == IsMineSigVersion::P2SH;
|
||||
}
|
||||
|
||||
bool HaveKeys(const std::vector<valtype>& pubkeys, const CWallet& keystore)
|
||||
{
|
||||
for (const valtype& pubkey : pubkeys) {
|
||||
CKeyID keyID = CPubKey(pubkey).GetID();
|
||||
if (!keystore.HaveKey(keyID)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
IsMineResult IsMineInner(const CWallet& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion)
|
||||
{
|
||||
IsMineResult ret = IsMineResult::NO;
|
||||
|
||||
std::vector<valtype> vSolutions;
|
||||
txnouttype whichType = Solver(scriptPubKey, vSolutions);
|
||||
|
||||
CKeyID keyID;
|
||||
switch (whichType)
|
||||
{
|
||||
case TX_NONSTANDARD:
|
||||
case TX_NULL_DATA:
|
||||
case TX_WITNESS_UNKNOWN:
|
||||
case TX_FEE:
|
||||
break;
|
||||
case TX_PUBKEY:
|
||||
keyID = CPubKey(vSolutions[0]).GetID();
|
||||
if (!PermitsUncompressed(sigversion) && vSolutions[0].size() != 33) {
|
||||
return IsMineResult::INVALID;
|
||||
}
|
||||
if (keystore.HaveKey(keyID)) {
|
||||
ret = std::max(ret, IsMineResult::SPENDABLE);
|
||||
}
|
||||
break;
|
||||
case TX_WITNESS_V0_KEYHASH:
|
||||
{
|
||||
if (sigversion == IsMineSigVersion::WITNESS_V0) {
|
||||
// P2WPKH inside P2WSH is invalid.
|
||||
return IsMineResult::INVALID;
|
||||
}
|
||||
if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) {
|
||||
// We do not support bare witness outputs unless the P2SH version of it would be
|
||||
// acceptable as well. This protects against matching before segwit activates.
|
||||
// This also applies to the P2WSH case.
|
||||
break;
|
||||
}
|
||||
ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(PKHash(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0));
|
||||
break;
|
||||
}
|
||||
case TX_PUBKEYHASH:
|
||||
keyID = CKeyID(uint160(vSolutions[0]));
|
||||
if (!PermitsUncompressed(sigversion)) {
|
||||
CPubKey pubkey;
|
||||
if (keystore.GetPubKey(keyID, pubkey) && !pubkey.IsCompressed()) {
|
||||
return IsMineResult::INVALID;
|
||||
}
|
||||
}
|
||||
if (keystore.HaveKey(keyID)) {
|
||||
ret = std::max(ret, IsMineResult::SPENDABLE);
|
||||
}
|
||||
break;
|
||||
case TX_SCRIPTHASH:
|
||||
{
|
||||
if (sigversion != IsMineSigVersion::TOP) {
|
||||
// P2SH inside P2WSH or P2SH is invalid.
|
||||
return IsMineResult::INVALID;
|
||||
}
|
||||
CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
|
||||
CScript subscript;
|
||||
if (keystore.GetCScript(scriptID, subscript)) {
|
||||
ret = std::max(ret, IsMineInner(keystore, subscript, IsMineSigVersion::P2SH));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TX_WITNESS_V0_SCRIPTHASH:
|
||||
{
|
||||
if (sigversion == IsMineSigVersion::WITNESS_V0) {
|
||||
// P2WSH inside P2WSH is invalid.
|
||||
return IsMineResult::INVALID;
|
||||
}
|
||||
if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) {
|
||||
break;
|
||||
}
|
||||
uint160 hash;
|
||||
CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(hash.begin());
|
||||
CScriptID scriptID = CScriptID(hash);
|
||||
CScript subscript;
|
||||
if (keystore.GetCScript(scriptID, subscript)) {
|
||||
ret = std::max(ret, IsMineInner(keystore, subscript, IsMineSigVersion::WITNESS_V0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TX_MULTISIG:
|
||||
{
|
||||
// Never treat bare multisig outputs as ours (they can still be made watchonly-though)
|
||||
if (sigversion == IsMineSigVersion::TOP) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Only consider transactions "mine" if we own ALL the
|
||||
// keys involved. Multi-signature transactions that are
|
||||
// partially owned (somebody else has a key that can spend
|
||||
// them) enable spend-out-from-under-you attacks, especially
|
||||
// in shared-wallet situations.
|
||||
std::vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
|
||||
if (!PermitsUncompressed(sigversion)) {
|
||||
for (size_t i = 0; i < keys.size(); i++) {
|
||||
if (keys[i].size() != 33) {
|
||||
return IsMineResult::INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (HaveKeys(keys, keystore)) {
|
||||
ret = std::max(ret, IsMineResult::SPENDABLE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TX_TRUE:
|
||||
if (Params().anyonecanspend_aremine) {
|
||||
return IsMineResult::SPENDABLE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == IsMineResult::NO && keystore.HaveWatchOnly(scriptPubKey)) {
|
||||
ret = std::max(ret, IsMineResult::WATCH_ONLY);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
isminetype IsMine(const CWallet& keystore, const CScript& scriptPubKey)
|
||||
{
|
||||
switch (IsMineInner(keystore, scriptPubKey, IsMineSigVersion::TOP)) {
|
||||
case IsMineResult::INVALID:
|
||||
case IsMineResult::NO:
|
||||
return ISMINE_NO;
|
||||
case IsMineResult::WATCH_ONLY:
|
||||
return ISMINE_WATCH_ONLY;
|
||||
case IsMineResult::SPENDABLE:
|
||||
return ISMINE_SPENDABLE;
|
||||
}
|
||||
assert(false);
|
||||
}
|
||||
|
||||
isminetype IsMine(const CWallet& keystore, const CTxDestination& dest)
|
||||
{
|
||||
CScript script = GetScriptForDestination(dest);
|
||||
return IsMine(keystore, script);
|
||||
}
|
||||
|
|
@ -28,9 +28,6 @@ enum isminetype : unsigned int
|
|||
/** used for bitflags of isminetype */
|
||||
typedef uint8_t isminefilter;
|
||||
|
||||
isminetype IsMine(const CWallet& wallet, const CScript& scriptPubKey);
|
||||
isminetype IsMine(const CWallet& wallet, const CTxDestination& dest);
|
||||
|
||||
/**
|
||||
* Cachable amount subdivided into watchonly and spendable parts.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ TransactionError FillPSBTInputsData(const CWallet* pwallet, PartiallySignedTrans
|
|||
}
|
||||
|
||||
// Get key origin info for input, if bip32derivs is true. Does not actually sign anything.
|
||||
SignPSBTInput(HidingSigningProvider(pwallet, true /* don't sign */, !bip32derivs), psbtx, i, 1 /* SIGHASH_ALL, ignored */);
|
||||
SignPSBTInput(HidingSigningProvider(pwallet->GetSigningProvider(), true /* don't sign */, !bip32derivs), psbtx, i, 1 /* SIGHASH_ALL, ignored */);
|
||||
}
|
||||
|
||||
return TransactionError::OK;
|
||||
|
|
@ -131,7 +131,7 @@ TransactionError SignPSBT(const CWallet* pwallet, PartiallySignedTransaction& ps
|
|||
}
|
||||
|
||||
// Here we _only_ sign, and do not e.g. fill in key origin data.
|
||||
complete &= SignPSBTInput(HidingSigningProvider(pwallet, !sign, true /* no key origins */), psbtx, i, sighash_type);
|
||||
complete &= SignPSBTInput(HidingSigningProvider(pwallet->GetSigningProvider(), !sign, true /* no key origins */), psbtx, i, sighash_type);
|
||||
}
|
||||
|
||||
// Restore the saved transaction, to remove our temporary munging.
|
||||
|
|
@ -153,7 +153,7 @@ void FillPSBTOutputsData(const CWallet* pwallet, PartiallySignedTransaction& psb
|
|||
psbt_out.FillSignatureData(sigdata);
|
||||
|
||||
MutableTransactionSignatureCreator creator(&tx, 0 /* nIn, ignored */, out.nValue, 1 /* sighashtype, ignored */);
|
||||
ProduceSignature(HidingSigningProvider(pwallet, true /* don't sign */, !bip32derivs), creator, out.scriptPubKey, sigdata);
|
||||
ProduceSignature(HidingSigningProvider(pwallet->GetSigningProvider(), true /* don't sign */, !bip32derivs), creator, out.scriptPubKey, sigdata);
|
||||
psbt_out.FromSignatureData(sigdata);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,11 +57,11 @@ static std::string DecodeDumpString(const std::string &str) {
|
|||
return ret.str();
|
||||
}
|
||||
|
||||
static bool GetWalletAddressesForKey(CWallet* const pwallet, const CKeyID& keyid, std::string& strAddr, std::string& strLabel) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
|
||||
static bool GetWalletAddressesForKey(LegacyScriptPubKeyMan* spk_man, CWallet* const pwallet, const CKeyID& keyid, std::string& strAddr, std::string& strLabel) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
|
||||
{
|
||||
bool fLabelFound = false;
|
||||
CKey key;
|
||||
pwallet->GetKey(keyid, key);
|
||||
spk_man->GetKey(keyid, key);
|
||||
for (const auto& dest : GetAllDestinationsForKey(key.GetPubKey())) {
|
||||
if (pwallet->mapAddressBook.count(dest)) {
|
||||
if (!strAddr.empty()) {
|
||||
|
|
@ -128,6 +128,11 @@ UniValue importprivkey(const JSONRPCRequest& request)
|
|||
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled");
|
||||
}
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
WalletRescanReserver reserver(pwallet);
|
||||
bool fRescan = true;
|
||||
{
|
||||
|
|
@ -254,6 +259,10 @@ UniValue importaddress(const JSONRPCRequest& request)
|
|||
},
|
||||
}.Check(request);
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
std::string strLabel;
|
||||
if (!request.params[1].isNull())
|
||||
|
|
@ -456,6 +465,10 @@ UniValue importpubkey(const JSONRPCRequest& request)
|
|||
},
|
||||
}.Check(request);
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
std::string strLabel;
|
||||
if (!request.params[1].isNull())
|
||||
|
|
@ -539,6 +552,11 @@ UniValue importwallet(const JSONRPCRequest& request)
|
|||
},
|
||||
}.Check(request);
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
if (pwallet->chain().havePruned()) {
|
||||
// Exit early and print an error.
|
||||
// If a block is pruned after this check, we will import the key(s),
|
||||
|
|
@ -696,6 +714,11 @@ UniValue dumpprivkey(const JSONRPCRequest& request)
|
|||
},
|
||||
}.Check(request);
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
auto locked_chain = pwallet->chain().lock();
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
|
|
@ -706,12 +729,12 @@ UniValue dumpprivkey(const JSONRPCRequest& request)
|
|||
if (!IsValidDestination(dest)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
|
||||
}
|
||||
auto keyid = GetKeyForDestination(*pwallet, dest);
|
||||
auto keyid = GetKeyForDestination(*spk_man, dest);
|
||||
if (keyid.IsNull()) {
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
|
||||
}
|
||||
CKey vchSecret;
|
||||
if (!pwallet->GetKey(keyid, vchSecret)) {
|
||||
if (!spk_man->GetKey(keyid, vchSecret)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
|
||||
}
|
||||
return EncodeSecret(vchSecret);
|
||||
|
|
@ -745,8 +768,14 @@ UniValue dumpwallet(const JSONRPCRequest& request)
|
|||
},
|
||||
}.Check(request);
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
auto locked_chain = pwallet->chain().lock();
|
||||
LOCK(pwallet->cs_wallet);
|
||||
AssertLockHeld(spk_man->cs_wallet);
|
||||
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
|
||||
|
|
@ -768,10 +797,10 @@ UniValue dumpwallet(const JSONRPCRequest& request)
|
|||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
|
||||
|
||||
std::map<CKeyID, int64_t> mapKeyBirth;
|
||||
const std::map<CKeyID, int64_t>& mapKeyPool = pwallet->GetAllReserveKeys();
|
||||
const std::map<CKeyID, int64_t>& mapKeyPool = spk_man->GetAllReserveKeys();
|
||||
pwallet->GetKeyBirthTimes(*locked_chain, mapKeyBirth);
|
||||
|
||||
std::set<CScriptID> scripts = pwallet->GetCScripts();
|
||||
std::set<CScriptID> scripts = spk_man->GetCScripts();
|
||||
|
||||
// sort time/key pairs
|
||||
std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;
|
||||
|
|
@ -790,11 +819,11 @@ UniValue dumpwallet(const JSONRPCRequest& request)
|
|||
file << "\n";
|
||||
|
||||
// add the base58check encoded extended master if the wallet uses HD
|
||||
CKeyID seed_id = pwallet->GetHDChain().seed_id;
|
||||
CKeyID seed_id = spk_man->GetHDChain().seed_id;
|
||||
if (!seed_id.IsNull())
|
||||
{
|
||||
CKey seed;
|
||||
if (pwallet->GetKey(seed_id, seed)) {
|
||||
if (spk_man->GetKey(seed_id, seed)) {
|
||||
CExtKey masterKey;
|
||||
masterKey.SetSeed(seed.begin(), seed.size());
|
||||
|
||||
|
|
@ -811,20 +840,20 @@ UniValue dumpwallet(const JSONRPCRequest& request)
|
|||
std::string strAddr;
|
||||
std::string strLabel;
|
||||
CKey key;
|
||||
if (pwallet->GetKey(keyid, key)) {
|
||||
if (spk_man->GetKey(keyid, key)) {
|
||||
file << strprintf("%s %s ", EncodeSecret(key), strTime);
|
||||
if (GetWalletAddressesForKey(pwallet, keyid, strAddr, strLabel)) {
|
||||
if (GetWalletAddressesForKey(spk_man, pwallet, keyid, strAddr, strLabel)) {
|
||||
file << strprintf("label=%s", strLabel);
|
||||
} else if (keyid == seed_id) {
|
||||
file << "hdseed=1";
|
||||
} else if (mapKeyPool.count(keyid)) {
|
||||
file << "reserve=1";
|
||||
} else if (pwallet->mapKeyMetadata[keyid].hdKeypath == "s") {
|
||||
} else if (spk_man->mapKeyMetadata[keyid].hdKeypath == "s") {
|
||||
file << "inactivehdseed=1";
|
||||
} else {
|
||||
file << "change=1";
|
||||
}
|
||||
file << strprintf(" # addr=%s%s\n", strAddr, (pwallet->mapKeyMetadata[keyid].has_key_origin ? " hdkeypath="+WriteHDKeypath(pwallet->mapKeyMetadata[keyid].key_origin.path) : ""));
|
||||
file << strprintf(" # addr=%s%s\n", strAddr, (spk_man->mapKeyMetadata[keyid].has_key_origin ? " hdkeypath="+WriteHDKeypath(spk_man->mapKeyMetadata[keyid].key_origin.path) : ""));
|
||||
}
|
||||
}
|
||||
file << "\n";
|
||||
|
|
@ -833,11 +862,11 @@ UniValue dumpwallet(const JSONRPCRequest& request)
|
|||
std::string create_time = "0";
|
||||
std::string address = EncodeDestination(ScriptHash(scriptid));
|
||||
// get birth times for scripts with metadata
|
||||
auto it = pwallet->m_script_metadata.find(scriptid);
|
||||
if (it != pwallet->m_script_metadata.end()) {
|
||||
auto it = spk_man->m_script_metadata.find(scriptid);
|
||||
if (it != spk_man->m_script_metadata.end()) {
|
||||
create_time = FormatISO8601DateTime(it->second.nCreateTime);
|
||||
}
|
||||
if(pwallet->GetCScript(scriptid, script)) {
|
||||
if(spk_man->GetCScript(scriptid, script)) {
|
||||
file << strprintf("%s %s script=1", HexStr(script.begin(), script.end()), create_time);
|
||||
file << strprintf(" # addr=%s\n", address);
|
||||
}
|
||||
|
|
@ -1230,7 +1259,7 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
|
|||
|
||||
// Check whether we have any work to do
|
||||
for (const CScript& script : script_pub_keys) {
|
||||
if (::IsMine(*pwallet, script) & ISMINE_SPENDABLE) {
|
||||
if (pwallet->IsMine(script) & ISMINE_SPENDABLE) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script (\"" + HexStr(script.begin(), script.end()) + "\")");
|
||||
}
|
||||
|
||||
|
|
@ -1359,6 +1388,11 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
|
|||
|
||||
RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ});
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
const UniValue& requests = mainRequest.params[0];
|
||||
|
||||
//Default options
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ static bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWall
|
|||
|
||||
|
||||
/** Checks if a CKey is in the given CWallet compressed or otherwise*/
|
||||
bool HaveKey(const CWallet& wallet, const CKey& key)
|
||||
bool HaveKey(const SigningProvider& wallet, const CKey& key)
|
||||
{
|
||||
CKey key2;
|
||||
key2.Set(key.begin(), key.end(), !key.IsCompressed());
|
||||
|
|
@ -341,7 +341,7 @@ static UniValue setlabel(const JSONRPCRequest& request)
|
|||
|
||||
std::string label = LabelFromValue(request.params[1]);
|
||||
|
||||
if (IsMine(*pwallet, dest)) {
|
||||
if (pwallet->IsMine(dest)) {
|
||||
pwallet->SetAddressBook(dest, label, "receive");
|
||||
} else {
|
||||
pwallet->SetAddressBook(dest, label, "send");
|
||||
|
|
@ -610,9 +610,11 @@ static UniValue signmessage(const JSONRPCRequest& request)
|
|||
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
|
||||
}
|
||||
|
||||
const SigningProvider* provider = pwallet->GetSigningProvider();
|
||||
|
||||
CKey key;
|
||||
CKeyID keyID(*pkhash);
|
||||
if (!pwallet->GetKey(keyID, key)) {
|
||||
if (!provider->GetKey(keyID, key)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
|
||||
}
|
||||
|
||||
|
|
@ -671,7 +673,7 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request)
|
|||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
|
||||
}
|
||||
CScript scriptPubKey = GetScriptForDestination(dest);
|
||||
if (!IsMine(*pwallet, scriptPubKey)) {
|
||||
if (!pwallet->IsMine(scriptPubKey)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Address not found in wallet");
|
||||
}
|
||||
|
||||
|
|
@ -771,7 +773,7 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request)
|
|||
for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) {
|
||||
const CTxOut& txout = wtx.tx->vout[i];
|
||||
CTxDestination address;
|
||||
if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwallet, address) && setAddress.count(address)) {
|
||||
if (ExtractDestination(txout.scriptPubKey, address) && pwallet->IsMine(address) && setAddress.count(address)) {
|
||||
if (wtx.GetDepthInMainChain(*locked_chain) >= nMinDepth) {
|
||||
CAmountMap wtxValue;
|
||||
CAmount amt = wtx.GetOutputValueOut(i);
|
||||
|
|
@ -1097,6 +1099,11 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request)
|
|||
},
|
||||
}.Check(request);
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
auto locked_chain = pwallet->chain().lock();
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
|
|
@ -1113,7 +1120,7 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request)
|
|||
if (IsHex(keys_or_addrs[i].get_str()) && (keys_or_addrs[i].get_str().length() == 66 || keys_or_addrs[i].get_str().length() == 130)) {
|
||||
pubkeys.push_back(HexToPubKey(keys_or_addrs[i].get_str()));
|
||||
} else {
|
||||
pubkeys.push_back(AddrToPubKey(pwallet, keys_or_addrs[i].get_str()));
|
||||
pubkeys.push_back(AddrToPubKey(spk_man, keys_or_addrs[i].get_str()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1126,7 +1133,7 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request)
|
|||
|
||||
// Construct using pay-to-script-hash:
|
||||
CScript inner;
|
||||
CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, *pwallet, inner);
|
||||
CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, *spk_man, inner);
|
||||
pwallet->SetAddressBook(dest, label, "send");
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
|
|
@ -1138,17 +1145,17 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request)
|
|||
class Witnessifier : public boost::static_visitor<bool>
|
||||
{
|
||||
public:
|
||||
CWallet * const pwallet;
|
||||
const SigningProvider * const provider;
|
||||
CTxDestination result;
|
||||
bool already_witness;
|
||||
|
||||
explicit Witnessifier(CWallet *_pwallet) : pwallet(_pwallet), already_witness(false) {}
|
||||
explicit Witnessifier(const SigningProvider *_provider) : provider(_provider), already_witness(false) {}
|
||||
|
||||
bool operator()(const PKHash &keyID) {
|
||||
if (pwallet) {
|
||||
if (provider) {
|
||||
CScript basescript = GetScriptForDestination(keyID);
|
||||
CScript witscript = GetScriptForWitness(basescript);
|
||||
if (!IsSolvable(*pwallet, witscript)) {
|
||||
if (!IsSolvable(*provider, witscript)) {
|
||||
return false;
|
||||
}
|
||||
return ExtractDestination(witscript, result);
|
||||
|
|
@ -1158,7 +1165,7 @@ public:
|
|||
|
||||
bool operator()(const ScriptHash &scripthash) {
|
||||
CScript subscript;
|
||||
if (pwallet && pwallet->GetCScript(CScriptID(scripthash), subscript)) {
|
||||
if (provider && provider->GetCScript(CScriptID(scripthash), subscript)) {
|
||||
int witnessversion;
|
||||
std::vector<unsigned char> witprog;
|
||||
if (subscript.IsWitnessProgram(witnessversion, witprog)) {
|
||||
|
|
@ -1167,7 +1174,7 @@ public:
|
|||
return true;
|
||||
}
|
||||
CScript witscript = GetScriptForWitness(subscript);
|
||||
if (!IsSolvable(*pwallet, witscript)) {
|
||||
if (!IsSolvable(*provider, witscript)) {
|
||||
return false;
|
||||
}
|
||||
return ExtractDestination(witscript, result);
|
||||
|
|
@ -1266,7 +1273,7 @@ static UniValue ListReceived(interfaces::Chain::Lock& locked_chain, CWallet * co
|
|||
continue;
|
||||
}
|
||||
|
||||
isminefilter mine = IsMine(*pwallet, address);
|
||||
isminefilter mine = pwallet->IsMine(address);
|
||||
if(!(mine & filter))
|
||||
continue;
|
||||
|
||||
|
|
@ -1500,7 +1507,7 @@ static void ListTransactions(interfaces::Chain::Lock& locked_chain, CWallet* con
|
|||
for (const COutputEntry& s : listSent)
|
||||
{
|
||||
UniValue entry(UniValue::VOBJ);
|
||||
if (involvesWatchonly || (::IsMine(*pwallet, s.destination) & ISMINE_WATCH_ONLY)) {
|
||||
if (involvesWatchonly || (pwallet->IsMine(s.destination) & ISMINE_WATCH_ONLY)) {
|
||||
entry.pushKV("involvesWatchonly", true);
|
||||
}
|
||||
MaybePushAddress(entry, s.destination);
|
||||
|
|
@ -1536,7 +1543,7 @@ static void ListTransactions(interfaces::Chain::Lock& locked_chain, CWallet* con
|
|||
continue;
|
||||
}
|
||||
UniValue entry(UniValue::VOBJ);
|
||||
if (involvesWatchonly || (::IsMine(*pwallet, r.destination) & ISMINE_WATCH_ONLY)) {
|
||||
if (involvesWatchonly || (pwallet->IsMine(r.destination) & ISMINE_WATCH_ONLY)) {
|
||||
entry.pushKV("involvesWatchonly", true);
|
||||
}
|
||||
MaybePushAddress(entry, r.destination);
|
||||
|
|
@ -2616,7 +2623,8 @@ static UniValue getbalances(const JSONRPCRequest& request)
|
|||
}
|
||||
balances.pushKV("mine", balances_mine);
|
||||
}
|
||||
if (wallet.HaveWatchOnly()) {
|
||||
auto spk_man = wallet.GetLegacyScriptPubKeyMan();
|
||||
if (spk_man && spk_man->HaveWatchOnly()) {
|
||||
UniValue balances_watchonly{UniValue::VOBJ};
|
||||
balances_watchonly.pushKV("trusted", AmountMapToUniv(bal.m_watchonly_trusted, ""));
|
||||
balances_watchonly.pushKV("untrusted_pending", AmountMapToUniv(bal.m_watchonly_untrusted_pending, ""));
|
||||
|
|
@ -2686,7 +2694,15 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
|
|||
obj.pushKV("txcount", (int)pwallet->mapWallet.size());
|
||||
obj.pushKV("keypoololdest", pwallet->GetOldestKeyPoolTime());
|
||||
obj.pushKV("keypoolsize", (int64_t)kpExternalSize);
|
||||
CKeyID seed_id = pwallet->GetHDChain().seed_id;
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (spk_man) {
|
||||
CKeyID seed_id = spk_man->GetHDChain().seed_id;
|
||||
if (!seed_id.IsNull()) {
|
||||
obj.pushKV("hdseedid", seed_id.GetHex());
|
||||
}
|
||||
}
|
||||
|
||||
if (pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) {
|
||||
obj.pushKV("keypoolsize_hd_internal", (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize));
|
||||
}
|
||||
|
|
@ -2694,9 +2710,6 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
|
|||
obj.pushKV("unlocked_until", pwallet->nRelockTime);
|
||||
}
|
||||
obj.pushKV("paytxfee", ValueFromAmount(pwallet->m_pay_tx_fee.GetFeePerK()));
|
||||
if (!seed_id.IsNull()) {
|
||||
obj.pushKV("hdseedid", seed_id.GetHex());
|
||||
}
|
||||
obj.pushKV("private_keys_enabled", !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
|
||||
obj.pushKV("avoid_reuse", pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE));
|
||||
if (pwallet->IsScanning()) {
|
||||
|
|
@ -3186,10 +3199,11 @@ static UniValue listunspent(const JSONRPCRequest& request)
|
|||
entry.pushKV("label", i->second.name);
|
||||
}
|
||||
|
||||
const SigningProvider* provider = pwallet->GetSigningProvider();
|
||||
if (scriptPubKey.IsPayToScriptHash()) {
|
||||
const CScriptID& hash = CScriptID(boost::get<ScriptHash>(address));
|
||||
CScript redeemScript;
|
||||
if (pwallet->GetCScript(hash, redeemScript)) {
|
||||
if (provider->GetCScript(hash, redeemScript)) {
|
||||
entry.pushKV("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()));
|
||||
// Now check if the redeemScript is actually a P2WSH script
|
||||
CTxDestination witness_destination;
|
||||
|
|
@ -3201,7 +3215,7 @@ static UniValue listunspent(const JSONRPCRequest& request)
|
|||
CScriptID id;
|
||||
CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin());
|
||||
CScript witnessScript;
|
||||
if (pwallet->GetCScript(id, witnessScript)) {
|
||||
if (provider->GetCScript(id, witnessScript)) {
|
||||
entry.pushKV("witnessScript", HexStr(witnessScript.begin(), witnessScript.end()));
|
||||
}
|
||||
}
|
||||
|
|
@ -3211,7 +3225,7 @@ static UniValue listunspent(const JSONRPCRequest& request)
|
|||
CScriptID id;
|
||||
CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin());
|
||||
CScript witnessScript;
|
||||
if (pwallet->GetCScript(id, witnessScript)) {
|
||||
if (provider->GetCScript(id, witnessScript)) {
|
||||
entry.pushKV("witnessScript", HexStr(witnessScript.begin(), witnessScript.end()));
|
||||
}
|
||||
}
|
||||
|
|
@ -3234,7 +3248,7 @@ static UniValue listunspent(const JSONRPCRequest& request)
|
|||
entry.pushKV("spendable", out.fSpendable);
|
||||
entry.pushKV("solvable", out.fSolvable);
|
||||
if (out.fSolvable) {
|
||||
auto descriptor = InferDescriptor(scriptPubKey, *pwallet);
|
||||
auto descriptor = InferDescriptor(scriptPubKey, *pwallet->GetLegacyScriptPubKeyMan());
|
||||
entry.pushKV("desc", descriptor->ToString());
|
||||
}
|
||||
if (avoid_reuse) entry.pushKV("reused", reused);
|
||||
|
|
@ -3572,7 +3586,7 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request)
|
|||
// Parse the prevtxs array
|
||||
ParsePrevouts(request.params[1], nullptr, coins);
|
||||
|
||||
return SignTransaction(mtx, pwallet, coins, request.params[2]);
|
||||
return SignTransaction(mtx, &*pwallet->GetLegacyScriptPubKeyMan(), coins, request.params[2]);
|
||||
}
|
||||
|
||||
static UniValue bumpfee(const JSONRPCRequest& request)
|
||||
|
|
@ -3844,7 +3858,7 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
|
|||
class DescribeWalletAddressVisitor : public boost::static_visitor<UniValue>
|
||||
{
|
||||
public:
|
||||
CWallet * const pwallet;
|
||||
const SigningProvider * const provider;
|
||||
|
||||
void ProcessSubScript(const CScript& subscript, UniValue& obj) const
|
||||
{
|
||||
|
|
@ -3880,7 +3894,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
explicit DescribeWalletAddressVisitor(CWallet* _pwallet) : pwallet(_pwallet) {}
|
||||
explicit DescribeWalletAddressVisitor(const SigningProvider* _provider) : provider(_provider) {}
|
||||
|
||||
UniValue operator()(const CNoDestination& dest) const { return UniValue(UniValue::VOBJ); }
|
||||
|
||||
|
|
@ -3889,7 +3903,7 @@ public:
|
|||
CKeyID keyID(pkhash);
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
CPubKey vchPubKey;
|
||||
if (pwallet && pwallet->GetPubKey(keyID, vchPubKey)) {
|
||||
if (provider && provider->GetPubKey(keyID, vchPubKey)) {
|
||||
obj.pushKV("pubkey", HexStr(vchPubKey));
|
||||
obj.pushKV("iscompressed", vchPubKey.IsCompressed());
|
||||
}
|
||||
|
|
@ -3901,7 +3915,7 @@ public:
|
|||
CScriptID scriptID(scripthash);
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
CScript subscript;
|
||||
if (pwallet && pwallet->GetCScript(scriptID, subscript)) {
|
||||
if (provider && provider->GetCScript(scriptID, subscript)) {
|
||||
ProcessSubScript(subscript, obj);
|
||||
}
|
||||
return obj;
|
||||
|
|
@ -3911,7 +3925,7 @@ public:
|
|||
{
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
CPubKey pubkey;
|
||||
if (pwallet && pwallet->GetPubKey(CKeyID(id), pubkey)) {
|
||||
if (provider && provider->GetPubKey(CKeyID(id), pubkey)) {
|
||||
obj.pushKV("pubkey", HexStr(pubkey));
|
||||
}
|
||||
return obj;
|
||||
|
|
@ -3924,7 +3938,7 @@ public:
|
|||
CRIPEMD160 hasher;
|
||||
uint160 hash;
|
||||
hasher.Write(id.begin(), 32).Finalize(hash.begin());
|
||||
if (pwallet && pwallet->GetCScript(CScriptID(hash), subscript)) {
|
||||
if (provider && provider->GetCScript(CScriptID(hash), subscript)) {
|
||||
ProcessSubScript(subscript, obj);
|
||||
}
|
||||
return obj;
|
||||
|
|
@ -3938,8 +3952,12 @@ static UniValue DescribeWalletAddress(CWallet* pwallet, const CTxDestination& de
|
|||
{
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
UniValue detail = DescribeAddress(dest);
|
||||
const SigningProvider* provider = nullptr;
|
||||
if (pwallet) {
|
||||
provider = pwallet->GetSigningProvider();
|
||||
}
|
||||
ret.pushKVs(detail);
|
||||
ret.pushKVs(boost::apply_visitor(DescribeWalletAddressVisitor(pwallet), dest));
|
||||
ret.pushKVs(boost::apply_visitor(DescribeWalletAddressVisitor(provider), dest));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -4108,18 +4126,19 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
|
|||
|
||||
CScript scriptPubKey = GetScriptForDestination(dest);
|
||||
ret.pushKV("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end()));
|
||||
const SigningProvider* provider = pwallet->GetSigningProvider();
|
||||
|
||||
isminetype mine = IsMine(*pwallet, dest);
|
||||
isminetype mine = pwallet->IsMine(dest);
|
||||
// Elements: Addresses we can not unblind outputs for aren't spendable
|
||||
if (IsBlindDestination(dest) &&
|
||||
GetDestinationBlindingKey(dest) != pwallet->GetBlindingPubKey(GetScriptForDestination(dest))) {
|
||||
mine = ISMINE_NO;
|
||||
}
|
||||
ret.pushKV("ismine", bool(mine & ISMINE_SPENDABLE));
|
||||
bool solvable = IsSolvable(*pwallet, scriptPubKey);
|
||||
bool solvable = IsSolvable(*provider, scriptPubKey);
|
||||
ret.pushKV("solvable", solvable);
|
||||
if (solvable) {
|
||||
ret.pushKV("desc", InferDescriptor(scriptPubKey, *pwallet)->ToString());
|
||||
ret.pushKV("desc", InferDescriptor(scriptPubKey, *provider)->ToString());
|
||||
}
|
||||
ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY));
|
||||
UniValue detail = DescribeWalletAddress(pwallet, dest);
|
||||
|
|
@ -4134,7 +4153,7 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
|
|||
}
|
||||
ret.pushKV("ischange", pwallet->IsChange(scriptPubKey));
|
||||
const CKeyMetadata* meta = nullptr;
|
||||
CKeyID key_id = GetKeyForDestination(*pwallet, dest);
|
||||
CKeyID key_id = GetKeyForDestination(*provider, dest);
|
||||
if (!key_id.IsNull()) {
|
||||
auto it = pwallet->mapKeyMetadata.find(key_id);
|
||||
if (it != pwallet->mapKeyMetadata.end()) {
|
||||
|
|
@ -4312,6 +4331,11 @@ UniValue sethdseed(const JSONRPCRequest& request)
|
|||
},
|
||||
}.Check(request);
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
if (pwallet->chain().isInitialBlockDownload()) {
|
||||
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Cannot set a new HD seed while still in Initial Block Download");
|
||||
}
|
||||
|
|
@ -4337,39 +4361,26 @@ UniValue sethdseed(const JSONRPCRequest& request)
|
|||
|
||||
CPubKey master_pub_key;
|
||||
if (request.params[1].isNull()) {
|
||||
master_pub_key = pwallet->GenerateNewSeed();
|
||||
master_pub_key = spk_man->GenerateNewSeed();
|
||||
} else {
|
||||
CKey key = DecodeSecret(request.params[1].get_str());
|
||||
if (!key.IsValid()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
|
||||
}
|
||||
|
||||
if (HaveKey(*pwallet, key)) {
|
||||
if (HaveKey(*spk_man, key)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key (either as an HD seed or as a loose private key)");
|
||||
}
|
||||
|
||||
master_pub_key = pwallet->DeriveNewSeed(key);
|
||||
master_pub_key = spk_man->DeriveNewSeed(key);
|
||||
}
|
||||
|
||||
pwallet->SetHDSeed(master_pub_key);
|
||||
if (flush_key_pool) pwallet->NewKeyPool();
|
||||
spk_man->SetHDSeed(master_pub_key);
|
||||
if (flush_key_pool) spk_man->NewKeyPool();
|
||||
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map<CPubKey, KeyOriginInfo>& hd_keypaths)
|
||||
{
|
||||
CPubKey vchPubKey;
|
||||
if (!pwallet->GetPubKey(keyID, vchPubKey)) {
|
||||
return;
|
||||
}
|
||||
KeyOriginInfo info;
|
||||
if (!pwallet->GetKeyOrigin(keyID, info)) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal keypath is broken");
|
||||
}
|
||||
hd_keypaths.emplace(vchPubKey, std::move(info));
|
||||
}
|
||||
|
||||
UniValue walletfillpsbtdata(const JSONRPCRequest& request)
|
||||
{
|
||||
if (!g_con_elementsmode)
|
||||
|
|
@ -4762,6 +4773,11 @@ UniValue signblock(const JSONRPCRequest& request)
|
|||
|
||||
LOCK(cs_main);
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
uint256 hash = block.GetHash();
|
||||
BlockMap::iterator mi = ::BlockIndex().find(hash);
|
||||
if (mi != ::BlockIndex().end())
|
||||
|
|
@ -4783,7 +4799,7 @@ UniValue signblock(const JSONRPCRequest& request)
|
|||
// Expose SignatureData internals in return value in lieu of "Partially Signed Bitcoin Blocks"
|
||||
SignatureData block_sigs;
|
||||
if (block.m_dynafed_params.IsNull()) {
|
||||
GenericSignScript(*pwallet, block.GetBlockHeader(), block.proof.challenge, block_sigs, SCRIPT_NO_SIGHASH_BYTE /* additional_flags */);
|
||||
GenericSignScript(*spk_man, block.GetBlockHeader(), block.proof.challenge, block_sigs, SCRIPT_NO_SIGHASH_BYTE /* additional_flags */);
|
||||
} else {
|
||||
if (request.params[1].isNull()) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Signing dynamic blocks requires the witnessScript argument");
|
||||
|
|
@ -4792,9 +4808,9 @@ UniValue signblock(const JSONRPCRequest& request)
|
|||
// Note that we're adding the signblockscript to the wallet so it can actually
|
||||
// satisfy witness program scriptpubkeys
|
||||
if (!witness_bytes.empty()) {
|
||||
pwallet->AddCScript(CScript(witness_bytes.begin(), witness_bytes.end()));
|
||||
spk_man->AddCScript(CScript(witness_bytes.begin(), witness_bytes.end()));
|
||||
}
|
||||
GenericSignScript(*pwallet, block.GetBlockHeader(), block.m_dynafed_params.m_current.m_signblockscript, block_sigs, SCRIPT_VERIFY_NONE /* additional_flags */);
|
||||
GenericSignScript(*spk_man, block.GetBlockHeader(), block.m_dynafed_params.m_current.m_signblockscript, block_sigs, SCRIPT_VERIFY_NONE /* additional_flags */);
|
||||
}
|
||||
|
||||
// Error if sig data didn't "grow"
|
||||
|
|
@ -4836,6 +4852,11 @@ UniValue getpeginaddress(const JSONRPCRequest& request)
|
|||
},
|
||||
}.ToString());
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
if (!pwallet->IsLocked()) {
|
||||
pwallet->TopUpKeyPool();
|
||||
}
|
||||
|
|
@ -4850,7 +4871,7 @@ UniValue getpeginaddress(const JSONRPCRequest& request)
|
|||
CScript dest_script = GetScriptForDestination(dest);
|
||||
|
||||
// Also add raw scripts to index to recognize later.
|
||||
pwallet->AddCScript(dest_script);
|
||||
spk_man->AddCScript(dest_script);
|
||||
|
||||
// Get P2CH deposit address on mainchain from most recent fedpegscript.
|
||||
const auto& fedpegscripts = GetValidFedpegScripts(::ChainActive().Tip(), Params().GetConsensus(), true /* nextblock_validation */);
|
||||
|
|
@ -4936,6 +4957,11 @@ UniValue initpegoutwallet(const JSONRPCRequest& request)
|
|||
auto locked_chain = pwallet->chain().lock();
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
// Check that network cares about PAK
|
||||
if (!Params().GetEnforcePak()) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "PAK enforcement is not enabled on this network.");
|
||||
|
|
@ -4956,7 +4982,7 @@ UniValue initpegoutwallet(const JSONRPCRequest& request)
|
|||
if (!online_pubkey.IsFullyValid()) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Given liquid_pak is not valid.");
|
||||
}
|
||||
if (!pwallet->HaveKey(online_pubkey.GetID())) {
|
||||
if (!spk_man->HaveKey(online_pubkey.GetID())) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error: liquid_pak could not be found in wallet");
|
||||
}
|
||||
}
|
||||
|
|
@ -5249,6 +5275,11 @@ UniValue sendtomainchain_pak(const JSONRPCRequest& request)
|
|||
std::string error;
|
||||
const auto descriptor = Parse(pwallet->offline_desc, provider, error);
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
// If descriptor not previously set, generate it
|
||||
if (!descriptor) {
|
||||
std::string offline_desc = "pkh(" + EncodeExtPubKey(xpub) + "0/*)";
|
||||
|
|
@ -5313,7 +5344,7 @@ UniValue sendtomainchain_pak(const JSONRPCRequest& request)
|
|||
|
||||
// Get online PAK
|
||||
CKey masterOnlineKey;
|
||||
if (!pwallet->GetKey(onlinepubkey.GetID(), masterOnlineKey))
|
||||
if (!spk_man->GetKey(onlinepubkey.GetID(), masterOnlineKey))
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Given online key is in master set but not in wallet");
|
||||
|
||||
// Tweak offline pubkey by tweakSum aka sumkey to get bitcoin key
|
||||
|
|
@ -6405,6 +6436,11 @@ UniValue generatepegoutproof(const JSONRPCRequest& request)
|
|||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pegout freeze is under effect to aid a pak transition to a new list. Please consult the network operator.");
|
||||
}
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
//Find PAK online pubkey on PAK list
|
||||
int whitelistindex=-1;
|
||||
std::vector<secp256k1_pubkey> pak_online = paklist.OnlineKeys();
|
||||
|
|
@ -6416,7 +6452,7 @@ UniValue generatepegoutproof(const JSONRPCRequest& request)
|
|||
throw JSONRPCError(RPC_WALLET_ERROR, "Given online key is not in Pegout Authorization Key List");
|
||||
|
||||
CKey masterOnlineKey;
|
||||
if (!pwallet->GetKey(onlinepubkey.GetID(), masterOnlineKey))
|
||||
if (!spk_man->GetKey(onlinepubkey.GetID(), masterOnlineKey))
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Given online key is in master set but not in wallet");
|
||||
|
||||
//Parse own offline pubkey
|
||||
|
|
@ -6478,6 +6514,11 @@ UniValue getpegoutkeys(const JSONRPCRequest& request)
|
|||
auto locked_chain = pwallet->chain().lock();
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
if (!request.params[1].isStr() || !IsHex(request.params[1].get_str()) || request.params[1].get_str().size() != 66) {
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "offlinepubkey must be hex string of size 66");
|
||||
}
|
||||
|
|
@ -6490,7 +6531,7 @@ UniValue getpegoutkeys(const JSONRPCRequest& request)
|
|||
}
|
||||
|
||||
CKey pegoutkey;
|
||||
if (!pwallet->GetKey(offline_pub.GetID(), pegoutkey))
|
||||
if (!spk_man->GetKey(offline_pub.GetID(), pegoutkey))
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Offline key can not be found in wallet");
|
||||
|
||||
CKey bitcoinkey = DecodeSecret(request.params[0].get_str());
|
||||
|
|
|
|||
1285
src/wallet/scriptpubkeyman.cpp
Normal file
1285
src/wallet/scriptpubkeyman.cpp
Normal file
File diff suppressed because it is too large
Load diff
356
src/wallet/scriptpubkeyman.h
Normal file
356
src/wallet/scriptpubkeyman.h
Normal file
|
|
@ -0,0 +1,356 @@
|
|||
// 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_WALLET_SCRIPTPUBKEYMAN_H
|
||||
#define BITCOIN_WALLET_SCRIPTPUBKEYMAN_H
|
||||
|
||||
#include <script/signingprovider.h>
|
||||
#include <script/standard.h>
|
||||
#include <wallet/crypter.h>
|
||||
#include <wallet/ismine.h>
|
||||
#include <wallet/walletdb.h>
|
||||
#include <wallet/walletutil.h>
|
||||
|
||||
#include <boost/signals2/signal.hpp>
|
||||
|
||||
enum class OutputType;
|
||||
|
||||
// Wallet storage things that ScriptPubKeyMans need in order to be able to store things to the wallet database.
|
||||
// It provides access to things that are part of the entire wallet and not specific to a ScriptPubKeyMan such as
|
||||
// wallet flags, wallet version, encryption keys, encryption status, and the database itself. This allows a
|
||||
// ScriptPubKeyMan to have callbacks into CWallet without causing a circular dependency.
|
||||
// WalletStorage should be the same for all ScriptPubKeyMans.
|
||||
class WalletStorage
|
||||
{
|
||||
public:
|
||||
virtual ~WalletStorage() = default;
|
||||
virtual const std::string GetDisplayName() const = 0;
|
||||
virtual WalletDatabase& GetDatabase() = 0;
|
||||
virtual bool IsWalletFlagSet(uint64_t) const = 0;
|
||||
virtual void SetWalletFlag(uint64_t) = 0;
|
||||
virtual void UnsetWalletFlagWithDB(WalletBatch&, uint64_t) = 0;
|
||||
virtual bool CanSupportFeature(enum WalletFeature) const = 0;
|
||||
virtual void SetMinVersion(enum WalletFeature, WalletBatch* = nullptr, bool = false) = 0;
|
||||
virtual bool IsLocked() const = 0;
|
||||
};
|
||||
|
||||
//! Default for -keypool
|
||||
static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
|
||||
|
||||
/** A key from a CWallet's keypool
|
||||
*
|
||||
* The wallet holds one (for pre HD-split wallets) or several keypools. These
|
||||
* are sets of keys that have not yet been used to provide addresses or receive
|
||||
* change.
|
||||
*
|
||||
* The Bitcoin Core wallet was originally a collection of unrelated private
|
||||
* keys with their associated addresses. If a non-HD wallet generated a
|
||||
* key/address, gave that address out and then restored a backup from before
|
||||
* that key's generation, then any funds sent to that address would be
|
||||
* lost definitively.
|
||||
*
|
||||
* The keypool was implemented to avoid this scenario (commit: 10384941). The
|
||||
* wallet would generate a set of keys (100 by default). When a new public key
|
||||
* was required, either to give out as an address or to use in a change output,
|
||||
* it would be drawn from the keypool. The keypool would then be topped up to
|
||||
* maintain 100 keys. This ensured that as long as the wallet hadn't used more
|
||||
* than 100 keys since the previous backup, all funds would be safe, since a
|
||||
* restored wallet would be able to scan for all owned addresses.
|
||||
*
|
||||
* A keypool also allowed encrypted wallets to give out addresses without
|
||||
* having to be decrypted to generate a new private key.
|
||||
*
|
||||
* With the introduction of HD wallets (commit: f1902510), the keypool
|
||||
* essentially became an address look-ahead pool. Restoring old backups can no
|
||||
* longer definitively lose funds as long as the addresses used were from the
|
||||
* wallet's HD seed (since all private keys can be rederived from the seed).
|
||||
* However, if many addresses were used since the backup, then the wallet may
|
||||
* not know how far ahead in the HD chain to look for its addresses. The
|
||||
* keypool is used to implement a 'gap limit'. The keypool maintains a set of
|
||||
* keys (by default 1000) ahead of the last used key and scans for the
|
||||
* addresses of those keys. This avoids the risk of not seeing transactions
|
||||
* involving the wallet's addresses, or of re-using the same address.
|
||||
*
|
||||
* The HD-split wallet feature added a second keypool (commit: 02592f4c). There
|
||||
* is an external keypool (for addresses to hand out) and an internal keypool
|
||||
* (for change addresses).
|
||||
*
|
||||
* Keypool keys are stored in the wallet/keystore's keymap. The keypool data is
|
||||
* stored as sets of indexes in the wallet (setInternalKeyPool,
|
||||
* setExternalKeyPool and set_pre_split_keypool), and a map from the key to the
|
||||
* index (m_pool_key_to_index). The CKeyPool object is used to
|
||||
* serialize/deserialize the pool data to/from the database.
|
||||
*/
|
||||
class CKeyPool
|
||||
{
|
||||
public:
|
||||
//! The time at which the key was generated. Set in AddKeypoolPubKeyWithDB
|
||||
int64_t nTime;
|
||||
//! The public key
|
||||
CPubKey vchPubKey;
|
||||
//! Whether this keypool entry is in the internal keypool (for change outputs)
|
||||
bool fInternal;
|
||||
//! Whether this key was generated for a keypool before the wallet was upgraded to HD-split
|
||||
bool m_pre_split;
|
||||
|
||||
CKeyPool();
|
||||
CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn);
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
int nVersion = s.GetVersion();
|
||||
if (!(s.GetType() & SER_GETHASH))
|
||||
READWRITE(nVersion);
|
||||
READWRITE(nTime);
|
||||
READWRITE(vchPubKey);
|
||||
if (ser_action.ForRead()) {
|
||||
try {
|
||||
READWRITE(fInternal);
|
||||
}
|
||||
catch (std::ios_base::failure&) {
|
||||
/* flag as external address if we can't read the internal boolean
|
||||
(this will be the case for any wallet before the HD chain split version) */
|
||||
fInternal = false;
|
||||
}
|
||||
try {
|
||||
READWRITE(m_pre_split);
|
||||
}
|
||||
catch (std::ios_base::failure&) {
|
||||
/* flag as postsplit address if we can't read the m_pre_split boolean
|
||||
(this will be the case for any wallet that upgrades to HD chain split)*/
|
||||
m_pre_split = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
READWRITE(fInternal);
|
||||
READWRITE(m_pre_split);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* A class implementing ScriptPubKeyMan manages some (or all) scriptPubKeys used in a wallet.
|
||||
* It contains the scripts and keys related to the scriptPubKeys it manages.
|
||||
* A ScriptPubKeyMan will be able to give out scriptPubKeys to be used, as well as marking
|
||||
* when a scriptPubKey has been used. It also handles when and how to store a scriptPubKey
|
||||
* and its related scripts and keys, including encryption.
|
||||
*/
|
||||
class ScriptPubKeyMan
|
||||
{
|
||||
protected:
|
||||
WalletStorage& m_storage;
|
||||
|
||||
public:
|
||||
ScriptPubKeyMan(WalletStorage& storage) : m_storage(storage) {}
|
||||
};
|
||||
|
||||
class LegacyScriptPubKeyMan : public ScriptPubKeyMan, public FillableSigningProvider
|
||||
{
|
||||
private:
|
||||
using CryptedKeyMap = std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char>>>;
|
||||
using WatchOnlySet = std::set<CScript>;
|
||||
using WatchKeyMap = std::map<CKeyID, CPubKey>;
|
||||
|
||||
//! will encrypt previously unencrypted keys
|
||||
bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
|
||||
|
||||
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);
|
||||
|
||||
WalletBatch *encrypted_batch GUARDED_BY(cs_wallet) = nullptr;
|
||||
|
||||
/* the HD chain data model (external chain counters) */
|
||||
CHDChain hdChain;
|
||||
|
||||
/* HD derive new child key (on internal or external chain) */
|
||||
void DeriveNewChildKey(WalletBatch& batch, CKeyMetadata& metadata, CKey& secret, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
||||
std::set<int64_t> setInternalKeyPool GUARDED_BY(cs_wallet);
|
||||
std::set<int64_t> setExternalKeyPool GUARDED_BY(cs_wallet);
|
||||
std::set<int64_t> set_pre_split_keypool GUARDED_BY(cs_wallet);
|
||||
int64_t m_max_keypool_index GUARDED_BY(cs_wallet) = 0;
|
||||
std::map<CKeyID, int64_t> m_pool_key_to_index;
|
||||
|
||||
int64_t nTimeFirstKey GUARDED_BY(cs_wallet) = 0;
|
||||
|
||||
/**
|
||||
* Private version of AddWatchOnly method which does not accept a
|
||||
* timestamp, and which will reset the wallet's nTimeFirstKey value to 1 if
|
||||
* the watch key did not previously have a timestamp associated with it.
|
||||
* Because this is an inherited virtual method, it is accessible despite
|
||||
* being marked private, but it is marked private anyway to encourage use
|
||||
* of the other AddWatchOnly which accepts a timestamp and sets
|
||||
* nTimeFirstKey more intelligently for more efficient rescans.
|
||||
*/
|
||||
bool AddWatchOnly(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 */
|
||||
bool AddKeyOriginWithDB(WalletBatch& batch, const CPubKey& pubkey, const KeyOriginInfo& info);
|
||||
|
||||
//! 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);
|
||||
|
||||
//! Adds a watch-only address to the store, and saves it to disk.
|
||||
bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest, int64_t create_time) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
||||
void AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const bool internal, WalletBatch& batch);
|
||||
|
||||
//! Adds a script to the store and saves it to disk
|
||||
bool AddCScriptWithDB(WalletBatch& batch, const CScript& script);
|
||||
|
||||
public:
|
||||
//! Fetches a key from the keypool
|
||||
bool GetKeyFromPool(CPubKey &key, bool internal = false);
|
||||
void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
void MarkPreSplitKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
||||
// Map from Key ID to key metadata.
|
||||
std::map<CKeyID, CKeyMetadata> mapKeyMetadata GUARDED_BY(cs_wallet);
|
||||
|
||||
// Map from Script ID to key metadata (for watch-only keys).
|
||||
std::map<CScriptID, CKeyMetadata> m_script_metadata GUARDED_BY(cs_wallet);
|
||||
|
||||
/**
|
||||
* keystore implementation
|
||||
* Generate a new key
|
||||
*/
|
||||
CPubKey GenerateNewKey(WalletBatch& batch, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
//! 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 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);
|
||||
//! Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo
|
||||
void UpgradeKeyMetadata() 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.
|
||||
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);
|
||||
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 LoadCScript(const CScript& redeemScript);
|
||||
|
||||
//! 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 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;
|
||||
|
||||
bool ImportScripts(const std::set<CScript> scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
bool ImportPrivKeys(const std::map<CKeyID, CKey>& privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
bool ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const bool internal, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
bool ImportScriptPubKeys(const std::string& label, const std::set<CScript>& script_pub_keys, const bool have_solving_data, const bool apply_label, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
||||
bool NewKeyPool();
|
||||
size_t KeypoolCountExternalKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
bool TopUpKeyPool(unsigned int kpSize = 0);
|
||||
|
||||
/**
|
||||
* Reserves a key from the keypool and sets nIndex to its index
|
||||
*
|
||||
* @param[out] nIndex the index of the key in keypool
|
||||
* @param[out] keypool the keypool the key was drawn from, which could be the
|
||||
* the pre-split pool if present, or the internal or external pool
|
||||
* @param fRequestedInternal true if the caller would like the key drawn
|
||||
* from the internal keypool, false if external is preferred
|
||||
*
|
||||
* @return true if succeeded, false if failed due to empty keypool
|
||||
* @throws std::runtime_error if keypool read failed, key was invalid,
|
||||
* was not found in the wallet, or was misclassified in the internal
|
||||
* or external keypool
|
||||
*/
|
||||
bool ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal);
|
||||
void KeepKey(int64_t nIndex);
|
||||
void ReturnKey(int64_t nIndex, bool fInternal, const CPubKey& pubkey);
|
||||
int64_t GetOldestKeyPoolTime();
|
||||
/**
|
||||
* Marks all keys in the keypool up to and including reserve_key as used.
|
||||
*/
|
||||
void MarkReserveKeysAsUsed(int64_t keypool_id) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
const std::map<CKeyID, int64_t>& GetAllReserveKeys() const { return m_pool_key_to_index; }
|
||||
bool GetNewDestination(const OutputType type, const std::string label, CTxDestination& dest, std::string& error, bool add_blinding_key);
|
||||
|
||||
isminetype IsMine(const CScript& script) const;
|
||||
|
||||
/* Set the HD chain model (chain child index counters) */
|
||||
void SetHDChain(const CHDChain& chain, bool memonly);
|
||||
const CHDChain& GetHDChain() const { return hdChain; }
|
||||
|
||||
/* Returns true if HD is enabled */
|
||||
bool IsHDEnabled() const;
|
||||
|
||||
/* Returns true if the wallet can generate new keys */
|
||||
bool CanGenerateKeys();
|
||||
|
||||
/* Returns true if the wallet can give out new addresses. This means it has keys in the keypool or can generate new keys */
|
||||
bool CanGetAddresses(bool internal = false);
|
||||
|
||||
/* Generates a new HD seed (will not be activated) */
|
||||
CPubKey GenerateNewSeed();
|
||||
|
||||
/* Derives a new HD seed (will not be activated) */
|
||||
CPubKey DeriveNewSeed(const CKey& key);
|
||||
|
||||
/* Set the current HD seed (will reset the chain child index counters)
|
||||
Sets the seed's version based on the current wallet version (so the
|
||||
caller must ensure the current wallet version is correct before calling
|
||||
this function). */
|
||||
void SetHDSeed(const CPubKey& key);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* software, as FillableSigningProvider automatically does this implicitly for all
|
||||
* keys now.
|
||||
*/
|
||||
void LearnRelatedScripts(const CPubKey& key, OutputType);
|
||||
|
||||
/**
|
||||
* Same as LearnRelatedScripts, but when the OutputType is not known (and could
|
||||
* be anything).
|
||||
*/
|
||||
void LearnAllRelatedScripts(const CPubKey& key);
|
||||
|
||||
/** Implement lookup of key origin information through wallet key metadata. */
|
||||
bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
|
||||
|
||||
// Temporary CWallet accessors and aliases.
|
||||
friend class CWallet;
|
||||
friend class ReserveDestination;
|
||||
LegacyScriptPubKeyMan(CWallet& wallet);
|
||||
bool SetCrypted();
|
||||
bool IsCrypted() const;
|
||||
void NotifyWatchonlyChanged(bool fHaveWatchOnly) const;
|
||||
void NotifyCanGetAddressesChanged() const;
|
||||
template<typename... Params> void WalletLogPrintf(const std::string& fmt, const Params&... parameters) const;
|
||||
CWallet& m_wallet;
|
||||
CCriticalSection& cs_wallet;
|
||||
CKeyingMaterial& vMasterKey GUARDED_BY(cs_KeyStore);
|
||||
std::atomic<bool>& fUseCrypto;
|
||||
bool& fDecryptionThoroughlyChecked;
|
||||
CPubKey GetBlindingPubKey(const CScript& script) const;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_WALLET_SCRIPTPUBKEYMAN_H
|
||||
|
|
@ -38,12 +38,12 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
|
||||
|
||||
// Keystore does not have key
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
|
||||
// Keystore has key
|
||||
BOOST_CHECK(keystore.AddKey(keys[0]));
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
|
||||
}
|
||||
|
||||
|
|
@ -54,12 +54,12 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
|
||||
|
||||
// Keystore does not have key
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
|
||||
// Keystore has key
|
||||
BOOST_CHECK(keystore.AddKey(uncompressedKey));
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
|
||||
}
|
||||
|
||||
|
|
@ -70,12 +70,12 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0]));
|
||||
|
||||
// Keystore does not have key
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
|
||||
// Keystore has key
|
||||
BOOST_CHECK(keystore.AddKey(keys[0]));
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
|
||||
}
|
||||
|
||||
|
|
@ -86,12 +86,12 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey));
|
||||
|
||||
// Keystore does not have key
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
|
||||
// Keystore has key
|
||||
BOOST_CHECK(keystore.AddKey(uncompressedKey));
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
|
||||
}
|
||||
|
||||
|
|
@ -104,17 +104,17 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
|
||||
|
||||
// Keystore does not have redeemScript or key
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
|
||||
// Keystore has redeemScript but no key
|
||||
BOOST_CHECK(keystore.AddCScript(redeemScript));
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemScript));
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
|
||||
// Keystore has redeemScript and key
|
||||
BOOST_CHECK(keystore.AddKey(keys[0]));
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
|
||||
}
|
||||
|
||||
|
|
@ -127,11 +127,11 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
CScript redeemscript = GetScriptForDestination(ScriptHash(redeemscript_inner));
|
||||
scriptPubKey = GetScriptForDestination(ScriptHash(redeemscript));
|
||||
|
||||
BOOST_CHECK(keystore.AddCScript(redeemscript));
|
||||
BOOST_CHECK(keystore.AddCScript(redeemscript_inner));
|
||||
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
|
||||
BOOST_CHECK(keystore.AddKey(keys[0]));
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemscript));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemscript_inner));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
}
|
||||
|
||||
|
|
@ -144,11 +144,11 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
CScript witnessscript = GetScriptForDestination(ScriptHash(redeemscript));
|
||||
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
|
||||
|
||||
BOOST_CHECK(keystore.AddCScript(witnessscript));
|
||||
BOOST_CHECK(keystore.AddCScript(redeemscript));
|
||||
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
|
||||
BOOST_CHECK(keystore.AddKey(keys[0]));
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessscript));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemscript));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
}
|
||||
|
||||
|
|
@ -160,10 +160,10 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
CScript witnessscript = GetScriptForDestination(WitnessV0KeyHash(PKHash(pubkeys[0])));
|
||||
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
|
||||
|
||||
BOOST_CHECK(keystore.AddCScript(witnessscript));
|
||||
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
|
||||
BOOST_CHECK(keystore.AddKey(keys[0]));
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessscript));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
}
|
||||
|
||||
|
|
@ -176,11 +176,11 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
CScript witnessscript = GetScriptForDestination(WitnessV0ScriptHash(witnessscript_inner));
|
||||
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
|
||||
|
||||
BOOST_CHECK(keystore.AddCScript(witnessscript_inner));
|
||||
BOOST_CHECK(keystore.AddCScript(witnessscript));
|
||||
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
|
||||
BOOST_CHECK(keystore.AddKey(keys[0]));
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessscript_inner));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessscript));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
}
|
||||
|
||||
|
|
@ -188,13 +188,13 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
|
||||
LOCK(keystore.cs_wallet);
|
||||
BOOST_CHECK(keystore.AddKey(keys[0]));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
|
||||
|
||||
scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(PKHash(pubkeys[0])));
|
||||
|
||||
// Keystore implicitly has key and P2SH redeemScript
|
||||
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
|
||||
}
|
||||
|
||||
|
|
@ -202,17 +202,17 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
|
||||
LOCK(keystore.cs_wallet);
|
||||
BOOST_CHECK(keystore.AddKey(uncompressedKey));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
|
||||
|
||||
scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(PKHash(uncompressedPubkey)));
|
||||
|
||||
// Keystore has key, but no P2SH redeemScript
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
|
||||
// Keystore has key and P2SH redeemScript
|
||||
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
}
|
||||
|
||||
|
|
@ -224,25 +224,25 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
scriptPubKey = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
|
||||
|
||||
// Keystore does not have any keys
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
|
||||
// Keystore has 1/2 keys
|
||||
BOOST_CHECK(keystore.AddKey(uncompressedKey));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
|
||||
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
|
||||
// Keystore has 2/2 keys
|
||||
BOOST_CHECK(keystore.AddKey(keys[1]));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
|
||||
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
|
||||
// Keystore has 2/2 keys and the script
|
||||
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
|
||||
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
}
|
||||
|
||||
|
|
@ -250,19 +250,19 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
|
||||
LOCK(keystore.cs_wallet);
|
||||
BOOST_CHECK(keystore.AddKey(uncompressedKey));
|
||||
BOOST_CHECK(keystore.AddKey(keys[1]));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
|
||||
|
||||
CScript redeemScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
|
||||
scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
|
||||
|
||||
// Keystore has no redeemScript
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
|
||||
// Keystore has redeemScript
|
||||
BOOST_CHECK(keystore.AddCScript(redeemScript));
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemScript));
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
|
||||
}
|
||||
|
||||
|
|
@ -270,24 +270,24 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
|
||||
LOCK(keystore.cs_wallet);
|
||||
BOOST_CHECK(keystore.AddKey(keys[0]));
|
||||
BOOST_CHECK(keystore.AddKey(keys[1]));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
|
||||
|
||||
CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
|
||||
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
|
||||
|
||||
// Keystore has keys, but no witnessScript or P2SH redeemScript
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
|
||||
// Keystore has keys and witnessScript, but no P2SH redeemScript
|
||||
BOOST_CHECK(keystore.AddCScript(witnessScript));
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessScript));
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
|
||||
// Keystore has keys, witnessScript, P2SH redeemScript
|
||||
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
|
||||
}
|
||||
|
||||
|
|
@ -295,24 +295,24 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
|
||||
LOCK(keystore.cs_wallet);
|
||||
BOOST_CHECK(keystore.AddKey(uncompressedKey));
|
||||
BOOST_CHECK(keystore.AddKey(keys[1]));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
|
||||
|
||||
CScript witnessScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
|
||||
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
|
||||
|
||||
// Keystore has keys, but no witnessScript or P2SH redeemScript
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
|
||||
// Keystore has keys and witnessScript, but no P2SH redeemScript
|
||||
BOOST_CHECK(keystore.AddCScript(witnessScript));
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessScript));
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
|
||||
// Keystore has keys, witnessScript, P2SH redeemScript
|
||||
BOOST_CHECK(keystore.AddCScript(scriptPubKey));
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
}
|
||||
|
||||
|
|
@ -326,19 +326,19 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
|
||||
|
||||
// Keystore has no witnessScript, P2SH redeemScript, or keys
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
|
||||
// Keystore has witnessScript and P2SH redeemScript, but no keys
|
||||
BOOST_CHECK(keystore.AddCScript(redeemScript));
|
||||
BOOST_CHECK(keystore.AddCScript(witnessScript));
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemScript));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessScript));
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
|
||||
// Keystore has keys, witnessScript, P2SH redeemScript
|
||||
BOOST_CHECK(keystore.AddKey(keys[0]));
|
||||
BOOST_CHECK(keystore.AddKey(keys[1]));
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
|
||||
}
|
||||
|
||||
|
|
@ -346,12 +346,12 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
|
||||
LOCK(keystore.cs_wallet);
|
||||
BOOST_CHECK(keystore.AddKey(keys[0]));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
|
||||
|
||||
scriptPubKey.clear();
|
||||
scriptPubKey << OP_RETURN << ToByteVector(pubkeys[0]);
|
||||
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
}
|
||||
|
||||
|
|
@ -359,12 +359,12 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
|
||||
LOCK(keystore.cs_wallet);
|
||||
BOOST_CHECK(keystore.AddKey(keys[0]));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
|
||||
|
||||
scriptPubKey.clear();
|
||||
scriptPubKey << OP_0 << ToByteVector(ParseHex("aabb"));
|
||||
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
}
|
||||
|
||||
|
|
@ -372,12 +372,12 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
|
||||
LOCK(keystore.cs_wallet);
|
||||
BOOST_CHECK(keystore.AddKey(keys[0]));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
|
||||
|
||||
scriptPubKey.clear();
|
||||
scriptPubKey << OP_16 << ToByteVector(ParseHex("aabb"));
|
||||
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
}
|
||||
|
||||
|
|
@ -385,12 +385,12 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
|
||||
LOCK(keystore.cs_wallet);
|
||||
BOOST_CHECK(keystore.AddKey(keys[0]));
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
|
||||
|
||||
scriptPubKey.clear();
|
||||
scriptPubKey << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
|
||||
|
||||
result = IsMine(keystore, scriptPubKey);
|
||||
result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ BOOST_FIXTURE_TEST_SUITE(psbt_wallet_tests, WalletTestingSetup)
|
|||
|
||||
BOOST_AUTO_TEST_CASE(psbt_updater_test)
|
||||
{
|
||||
auto spk_man = m_wallet.GetLegacyScriptPubKeyMan();
|
||||
LOCK(m_wallet.cs_wallet);
|
||||
|
||||
// Create prevtxs and add to wallet
|
||||
|
|
@ -35,23 +36,23 @@ BOOST_AUTO_TEST_CASE(psbt_updater_test)
|
|||
CScript rs1;
|
||||
CDataStream s_rs1(ParseHex("475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
s_rs1 >> rs1;
|
||||
m_wallet.AddCScript(rs1);
|
||||
spk_man->AddCScript(rs1);
|
||||
|
||||
CScript rs2;
|
||||
CDataStream s_rs2(ParseHex("2200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
s_rs2 >> rs2;
|
||||
m_wallet.AddCScript(rs2);
|
||||
spk_man->AddCScript(rs2);
|
||||
|
||||
CScript ws1;
|
||||
CDataStream s_ws1(ParseHex("47522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
s_ws1 >> ws1;
|
||||
m_wallet.AddCScript(ws1);
|
||||
spk_man->AddCScript(ws1);
|
||||
|
||||
// Add hd seed
|
||||
CKey key = DecodeSecret("5KSSJQ7UNfFGwVgpCZDSHm5rVNhMFcFtvWM3zQ8mW4qNDEN7LFd"); // Mainnet and uncompressed form of cUkG8i1RFfWGWy5ziR11zJ5V4U4W3viSFCfyJmZnvQaUsd1xuF3T
|
||||
CPubKey master_pub_key = m_wallet.DeriveNewSeed(key);
|
||||
m_wallet.SetHDSeed(master_pub_key);
|
||||
m_wallet.NewKeyPool();
|
||||
CPubKey master_pub_key = spk_man->DeriveNewSeed(key);
|
||||
spk_man->SetHDSeed(master_pub_key);
|
||||
spk_man->NewKeyPool();
|
||||
|
||||
PartiallySignedTransaction psbtx;
|
||||
CDataStream ssData(ParseHex("70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000000000000000000"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
|
|
|||
|
|
@ -27,8 +27,10 @@ BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup)
|
|||
|
||||
static void AddKey(CWallet& wallet, const CKey& key)
|
||||
{
|
||||
auto spk_man = wallet.GetLegacyScriptPubKeyMan();
|
||||
LOCK(wallet.cs_wallet);
|
||||
wallet.AddKeyPubKey(key, key.GetPubKey());
|
||||
AssertLockHeld(spk_man->cs_wallet);
|
||||
spk_man->AddKeyPubKey(key, key.GetPubKey());
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
|
||||
|
|
@ -194,9 +196,11 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
|
|||
// Import key into wallet and call dumpwallet to create backup file.
|
||||
{
|
||||
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
|
||||
auto spk_man = wallet->GetLegacyScriptPubKeyMan();
|
||||
LOCK(wallet->cs_wallet);
|
||||
wallet->mapKeyMetadata[coinbaseKey.GetPubKey().GetID()].nCreateTime = KEY_TIME;
|
||||
wallet->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
|
||||
AssertLockHeld(spk_man->cs_wallet);
|
||||
spk_man->mapKeyMetadata[coinbaseKey.GetPubKey().GetID()].nCreateTime = KEY_TIME;
|
||||
spk_man->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
|
||||
|
||||
JSONRPCRequest request;
|
||||
request.params.setArray();
|
||||
|
|
@ -242,11 +246,13 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
|
|||
auto chain = interfaces::MakeChain();
|
||||
|
||||
CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
|
||||
auto spk_man = wallet.GetLegacyScriptPubKeyMan();
|
||||
CWalletTx wtx(&wallet, m_coinbase_txns.back());
|
||||
|
||||
auto locked_chain = chain->lock();
|
||||
LockAssertion lock(::cs_main);
|
||||
LOCK(wallet.cs_wallet);
|
||||
AssertLockHeld(spk_man->cs_wallet);
|
||||
|
||||
wtx.SetConf(CWalletTx::Status::CONFIRMED, ::ChainActive().Tip()->GetBlockHash(), 0);
|
||||
|
||||
|
|
@ -254,10 +260,10 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
|
|||
// cache the current immature credit amount, which is 0.
|
||||
BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(*locked_chain)[CAsset()], 0);
|
||||
|
||||
// Invalidate the cached value, add the key, and make sure a new immature
|
||||
// Invalidate the cached vanue, add the key, and make sure a new immature
|
||||
// credit amount is calculated.
|
||||
wtx.MarkDirty();
|
||||
wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
|
||||
BOOST_CHECK(spk_man->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey()));
|
||||
BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(*locked_chain)[CAsset()], 50*COIN);
|
||||
}
|
||||
|
||||
|
|
@ -337,37 +343,38 @@ BOOST_AUTO_TEST_CASE(LoadReceiveRequests)
|
|||
BOOST_CHECK_EQUAL(values[1], "val_rr1");
|
||||
}
|
||||
|
||||
// Test some watch-only wallet methods by the procedure of loading (LoadWatchOnly),
|
||||
// Test some watch-only LegacyScriptPubKeyMan methods by the procedure of loading (LoadWatchOnly),
|
||||
// checking (HaveWatchOnly), getting (GetWatchPubKey) and removing (RemoveWatchOnly) a
|
||||
// given PubKey, resp. its corresponding P2PK Script. Results of the the impact on
|
||||
// the address -> PubKey map is dependent on whether the PubKey is a point on the curve
|
||||
static void TestWatchOnlyPubKey(CWallet& wallet, const CPubKey& add_pubkey)
|
||||
static void TestWatchOnlyPubKey(LegacyScriptPubKeyMan* spk_man, const CPubKey& add_pubkey)
|
||||
{
|
||||
CScript p2pk = GetScriptForRawPubKey(add_pubkey);
|
||||
CKeyID add_address = add_pubkey.GetID();
|
||||
CPubKey found_pubkey;
|
||||
LOCK(wallet.cs_wallet);
|
||||
LOCK(spk_man->cs_wallet);
|
||||
|
||||
// all Scripts (i.e. also all PubKeys) are added to the general watch-only set
|
||||
BOOST_CHECK(!wallet.HaveWatchOnly(p2pk));
|
||||
wallet.LoadWatchOnly(p2pk);
|
||||
BOOST_CHECK(wallet.HaveWatchOnly(p2pk));
|
||||
BOOST_CHECK(!spk_man->HaveWatchOnly(p2pk));
|
||||
spk_man->LoadWatchOnly(p2pk);
|
||||
BOOST_CHECK(spk_man->HaveWatchOnly(p2pk));
|
||||
|
||||
// only PubKeys on the curve shall be added to the watch-only address -> PubKey map
|
||||
bool is_pubkey_fully_valid = add_pubkey.IsFullyValid();
|
||||
if (is_pubkey_fully_valid) {
|
||||
BOOST_CHECK(wallet.GetWatchPubKey(add_address, found_pubkey));
|
||||
BOOST_CHECK(spk_man->GetWatchPubKey(add_address, found_pubkey));
|
||||
BOOST_CHECK(found_pubkey == add_pubkey);
|
||||
} else {
|
||||
BOOST_CHECK(!wallet.GetWatchPubKey(add_address, found_pubkey));
|
||||
BOOST_CHECK(!spk_man->GetWatchPubKey(add_address, found_pubkey));
|
||||
BOOST_CHECK(found_pubkey == CPubKey()); // passed key is unchanged
|
||||
}
|
||||
|
||||
wallet.RemoveWatchOnly(p2pk);
|
||||
BOOST_CHECK(!wallet.HaveWatchOnly(p2pk));
|
||||
AssertLockHeld(spk_man->cs_wallet);
|
||||
spk_man->RemoveWatchOnly(p2pk);
|
||||
BOOST_CHECK(!spk_man->HaveWatchOnly(p2pk));
|
||||
|
||||
if (is_pubkey_fully_valid) {
|
||||
BOOST_CHECK(!wallet.GetWatchPubKey(add_address, found_pubkey));
|
||||
BOOST_CHECK(!spk_man->GetWatchPubKey(add_address, found_pubkey));
|
||||
BOOST_CHECK(found_pubkey == add_pubkey); // passed key is unchanged
|
||||
}
|
||||
}
|
||||
|
|
@ -382,37 +389,38 @@ static void PollutePubKey(CPubKey& pubkey)
|
|||
assert(pubkey.IsValid());
|
||||
}
|
||||
|
||||
// Test watch-only wallet logic for PubKeys
|
||||
// Test watch-only logic for PubKeys
|
||||
BOOST_AUTO_TEST_CASE(WatchOnlyPubKeys)
|
||||
{
|
||||
CKey key;
|
||||
CPubKey pubkey;
|
||||
LegacyScriptPubKeyMan* spk_man = m_wallet.GetLegacyScriptPubKeyMan();
|
||||
|
||||
BOOST_CHECK(!m_wallet.HaveWatchOnly());
|
||||
BOOST_CHECK(!spk_man->HaveWatchOnly());
|
||||
|
||||
// uncompressed valid PubKey
|
||||
key.MakeNewKey(false);
|
||||
pubkey = key.GetPubKey();
|
||||
assert(!pubkey.IsCompressed());
|
||||
TestWatchOnlyPubKey(m_wallet, pubkey);
|
||||
TestWatchOnlyPubKey(spk_man, pubkey);
|
||||
|
||||
// uncompressed cryptographically invalid PubKey
|
||||
PollutePubKey(pubkey);
|
||||
TestWatchOnlyPubKey(m_wallet, pubkey);
|
||||
TestWatchOnlyPubKey(spk_man, pubkey);
|
||||
|
||||
// compressed valid PubKey
|
||||
key.MakeNewKey(true);
|
||||
pubkey = key.GetPubKey();
|
||||
assert(pubkey.IsCompressed());
|
||||
TestWatchOnlyPubKey(m_wallet, pubkey);
|
||||
TestWatchOnlyPubKey(spk_man, pubkey);
|
||||
|
||||
// compressed cryptographically invalid PubKey
|
||||
PollutePubKey(pubkey);
|
||||
TestWatchOnlyPubKey(m_wallet, pubkey);
|
||||
TestWatchOnlyPubKey(spk_man, pubkey);
|
||||
|
||||
// invalid empty PubKey
|
||||
pubkey = CPubKey();
|
||||
TestWatchOnlyPubKey(m_wallet, pubkey);
|
||||
TestWatchOnlyPubKey(spk_man, pubkey);
|
||||
}
|
||||
|
||||
class ListCoinsTestingSetup : public TestChain100Setup
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -19,7 +19,7 @@
|
|||
#include <validationinterface.h>
|
||||
#include <wallet/coinselection.h>
|
||||
#include <wallet/crypter.h>
|
||||
#include <wallet/ismine.h>
|
||||
#include <wallet/scriptpubkeyman.h>
|
||||
#include <wallet/walletdb.h>
|
||||
#include <wallet/walletutil.h>
|
||||
|
||||
|
|
@ -58,8 +58,6 @@ enum class WalletCreationStatus {
|
|||
|
||||
WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::vector<std::string>& warnings, std::shared_ptr<CWallet>& result);
|
||||
|
||||
//! Default for -keypool
|
||||
static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
|
||||
//! -paytxfee default
|
||||
constexpr CAmount DEFAULT_PAY_TX_FEE = 0;
|
||||
//! -fallbackfee default
|
||||
|
|
@ -100,58 +98,12 @@ struct FeeCalculation;
|
|||
enum class FeeEstimateMode;
|
||||
class ReserveDestination;
|
||||
|
||||
/** (client) version numbers for particular wallet features */
|
||||
enum WalletFeature
|
||||
{
|
||||
FEATURE_BASE = 10500, // the earliest version new wallets supports (only useful for getwalletinfo's clientversion output)
|
||||
|
||||
FEATURE_WALLETCRYPT = 40000, // wallet encryption
|
||||
FEATURE_COMPRPUBKEY = 60000, // compressed public keys
|
||||
|
||||
FEATURE_HD = 130000, // Hierarchical key derivation after BIP32 (HD Wallet)
|
||||
|
||||
FEATURE_HD_SPLIT = 139900, // Wallet with HD chain split (change outputs will use m/0'/1'/k)
|
||||
|
||||
FEATURE_NO_DEFAULT_KEY = 159900, // Wallet without a default key written
|
||||
|
||||
FEATURE_PRE_SPLIT_KEYPOOL = 169900, // Upgraded to HD SPLIT and can have a pre-split keypool
|
||||
|
||||
FEATURE_LATEST = FEATURE_PRE_SPLIT_KEYPOOL
|
||||
};
|
||||
|
||||
//! Default for -addresstype
|
||||
constexpr OutputType DEFAULT_ADDRESS_TYPE{OutputType::BECH32};
|
||||
|
||||
//! Default for -changetype
|
||||
constexpr OutputType DEFAULT_CHANGE_TYPE{OutputType::CHANGE_AUTO};
|
||||
|
||||
enum WalletFlags : uint64_t {
|
||||
// wallet flags in the upper section (> 1 << 31) will lead to not opening the wallet if flag is unknown
|
||||
// unknown wallet flags in the lower section <= (1 << 31) will be tolerated
|
||||
|
||||
// will categorize coins as clean (not reused) and dirty (reused), and handle
|
||||
// them with privacy considerations in mind
|
||||
WALLET_FLAG_AVOID_REUSE = (1ULL << 0),
|
||||
|
||||
// Indicates that the metadata has already been upgraded to contain key origins
|
||||
WALLET_FLAG_KEY_ORIGIN_METADATA = (1ULL << 1),
|
||||
|
||||
// will enforce the rule that the wallet can't contain any private keys (only watch-only/pubkeys)
|
||||
WALLET_FLAG_DISABLE_PRIVATE_KEYS = (1ULL << 32),
|
||||
|
||||
//! Flag set when a wallet contains no HD seed and no private keys, scripts,
|
||||
//! addresses, and other watch only things, and is therefore "blank."
|
||||
//!
|
||||
//! The only function this flag serves is to distinguish a blank wallet from
|
||||
//! a newly created wallet when the wallet database is loaded, to avoid
|
||||
//! initialization that should only happen on first run.
|
||||
//!
|
||||
//! This flag is also a mandatory flag to prevent previous versions of
|
||||
//! bitcoin from opening the wallet, thinking it was newly created, and
|
||||
//! then improperly reinitializing it.
|
||||
WALLET_FLAG_BLANK_WALLET = (1ULL << 33),
|
||||
};
|
||||
|
||||
static constexpr uint64_t KNOWN_WALLET_FLAGS =
|
||||
WALLET_FLAG_AVOID_REUSE
|
||||
| WALLET_FLAG_BLANK_WALLET
|
||||
|
|
@ -170,99 +122,6 @@ static const std::map<std::string,WalletFlags> WALLET_FLAG_MAP{
|
|||
|
||||
extern const std::map<uint64_t,std::string> WALLET_FLAG_CAVEATS;
|
||||
|
||||
/** A key from a CWallet's keypool
|
||||
*
|
||||
* The wallet holds one (for pre HD-split wallets) or several keypools. These
|
||||
* are sets of keys that have not yet been used to provide addresses or receive
|
||||
* change.
|
||||
*
|
||||
* The Bitcoin Core wallet was originally a collection of unrelated private
|
||||
* keys with their associated addresses. If a non-HD wallet generated a
|
||||
* key/address, gave that address out and then restored a backup from before
|
||||
* that key's generation, then any funds sent to that address would be
|
||||
* lost definitively.
|
||||
*
|
||||
* The keypool was implemented to avoid this scenario (commit: 10384941). The
|
||||
* wallet would generate a set of keys (100 by default). When a new public key
|
||||
* was required, either to give out as an address or to use in a change output,
|
||||
* it would be drawn from the keypool. The keypool would then be topped up to
|
||||
* maintain 100 keys. This ensured that as long as the wallet hadn't used more
|
||||
* than 100 keys since the previous backup, all funds would be safe, since a
|
||||
* restored wallet would be able to scan for all owned addresses.
|
||||
*
|
||||
* A keypool also allowed encrypted wallets to give out addresses without
|
||||
* having to be decrypted to generate a new private key.
|
||||
*
|
||||
* With the introduction of HD wallets (commit: f1902510), the keypool
|
||||
* essentially became an address look-ahead pool. Restoring old backups can no
|
||||
* longer definitively lose funds as long as the addresses used were from the
|
||||
* wallet's HD seed (since all private keys can be rederived from the seed).
|
||||
* However, if many addresses were used since the backup, then the wallet may
|
||||
* not know how far ahead in the HD chain to look for its addresses. The
|
||||
* keypool is used to implement a 'gap limit'. The keypool maintains a set of
|
||||
* keys (by default 1000) ahead of the last used key and scans for the
|
||||
* addresses of those keys. This avoids the risk of not seeing transactions
|
||||
* involving the wallet's addresses, or of re-using the same address.
|
||||
*
|
||||
* The HD-split wallet feature added a second keypool (commit: 02592f4c). There
|
||||
* is an external keypool (for addresses to hand out) and an internal keypool
|
||||
* (for change addresses).
|
||||
*
|
||||
* Keypool keys are stored in the wallet/keystore's keymap. The keypool data is
|
||||
* stored as sets of indexes in the wallet (setInternalKeyPool,
|
||||
* setExternalKeyPool and set_pre_split_keypool), and a map from the key to the
|
||||
* index (m_pool_key_to_index). The CKeyPool object is used to
|
||||
* serialize/deserialize the pool data to/from the database.
|
||||
*/
|
||||
class CKeyPool
|
||||
{
|
||||
public:
|
||||
//! The time at which the key was generated. Set in AddKeypoolPubKeyWithDB
|
||||
int64_t nTime;
|
||||
//! The public key
|
||||
CPubKey vchPubKey;
|
||||
//! Whether this keypool entry is in the internal keypool (for change outputs)
|
||||
bool fInternal;
|
||||
//! Whether this key was generated for a keypool before the wallet was upgraded to HD-split
|
||||
bool m_pre_split;
|
||||
|
||||
CKeyPool();
|
||||
CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn);
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
int nVersion = s.GetVersion();
|
||||
if (!(s.GetType() & SER_GETHASH))
|
||||
READWRITE(nVersion);
|
||||
READWRITE(nTime);
|
||||
READWRITE(vchPubKey);
|
||||
if (ser_action.ForRead()) {
|
||||
try {
|
||||
READWRITE(fInternal);
|
||||
}
|
||||
catch (std::ios_base::failure&) {
|
||||
/* flag as external address if we can't read the internal boolean
|
||||
(this will be the case for any wallet before the HD chain split version) */
|
||||
fInternal = false;
|
||||
}
|
||||
try {
|
||||
READWRITE(m_pre_split);
|
||||
}
|
||||
catch (std::ios_base::failure&) {
|
||||
/* flag as postsplit address if we can't read the m_pre_split boolean
|
||||
(this will be the case for any wallet that upgrades to HD chain split)*/
|
||||
m_pre_split = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
READWRITE(fInternal);
|
||||
READWRITE(m_pre_split);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** A wrapper to reserve an address from a wallet
|
||||
*
|
||||
* ReserveDestination is used to reserve an address.
|
||||
|
|
@ -283,6 +142,7 @@ class ReserveDestination
|
|||
protected:
|
||||
//! The wallet to reserve from
|
||||
CWallet* pwallet;
|
||||
LegacyScriptPubKeyMan* m_spk_man{nullptr};
|
||||
//! The index of the address's key in the keypool
|
||||
int64_t nIndex{-1};
|
||||
//! The public key for the address
|
||||
|
|
@ -814,10 +674,9 @@ struct BlindDetails {
|
|||
|
||||
class WalletRescanReserver; //forward declarations for ScanForWalletTransactions/RescanFromTime
|
||||
/**
|
||||
* 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.
|
||||
* A CWallet maintains a set of transactions and balances, and provides the ability to create new transactions.
|
||||
*/
|
||||
class CWallet final : public FillableSigningProvider, private interfaces::Chain::Notifications
|
||||
class CWallet final : public WalletStorage, private interfaces::Chain::Notifications
|
||||
{
|
||||
private:
|
||||
CKeyingMaterial vMasterKey GUARDED_BY(cs_KeyStore);
|
||||
|
|
@ -829,22 +688,8 @@ private:
|
|||
//! 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> fScanningWallet{false}; // controlled by WalletRescanReserver
|
||||
|
|
@ -853,8 +698,6 @@ private:
|
|||
std::mutex mutexScanning;
|
||||
friend class WalletRescanReserver;
|
||||
|
||||
WalletBatch *encrypted_batch GUARDED_BY(cs_wallet) = nullptr;
|
||||
|
||||
//! the current wallet version: clients below this version are not able to load the wallet
|
||||
int nWalletVersion GUARDED_BY(cs_wallet){FEATURE_BASE};
|
||||
|
||||
|
|
@ -904,52 +747,12 @@ private:
|
|||
* Should be called with non-zero block_hash and posInBlock if this is for a transaction that is included in a block. */
|
||||
void SyncTransaction(const CTransactionRef& tx, CWalletTx::Status status, const uint256& block_hash, int posInBlock = 0, bool update_tx = true) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
||||
/* the HD chain data model (external chain counters) */
|
||||
CHDChain hdChain;
|
||||
|
||||
/* HD derive new child key (on internal or external chain) */
|
||||
void DeriveNewChildKey(WalletBatch& batch, CKeyMetadata& metadata, CKey& secret, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
||||
std::set<int64_t> setInternalKeyPool GUARDED_BY(cs_wallet);
|
||||
std::set<int64_t> setExternalKeyPool GUARDED_BY(cs_wallet);
|
||||
std::set<int64_t> set_pre_split_keypool GUARDED_BY(cs_wallet);
|
||||
int64_t m_max_keypool_index GUARDED_BY(cs_wallet) = 0;
|
||||
std::map<CKeyID, int64_t> m_pool_key_to_index;
|
||||
std::atomic<uint64_t> m_wallet_flags{0};
|
||||
|
||||
int64_t nTimeFirstKey GUARDED_BY(cs_wallet) = 0;
|
||||
|
||||
/**
|
||||
* Private version of AddWatchOnly method which does not accept a
|
||||
* timestamp, and which will reset the wallet's nTimeFirstKey value to 1 if
|
||||
* the watch key did not previously have a timestamp associated with it.
|
||||
* Because this is an inherited virtual method, it is accessible despite
|
||||
* being marked private, but it is marked private anyway to encourage use
|
||||
* of the other AddWatchOnly which accepts a timestamp and sets
|
||||
* nTimeFirstKey more intelligently for more efficient rescans.
|
||||
*/
|
||||
bool AddWatchOnly(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 */
|
||||
bool AddKeyOriginWithDB(WalletBatch& batch, const CPubKey& pubkey, const KeyOriginInfo& info);
|
||||
|
||||
//! 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);
|
||||
|
||||
//! Adds a watch-only address to the store, and saves it to disk.
|
||||
bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest, int64_t create_time) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
||||
void AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const bool internal, WalletBatch& batch);
|
||||
|
||||
bool SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::string& strPurpose);
|
||||
|
||||
//! Adds a script to the store and saves it to disk
|
||||
bool AddCScriptWithDB(WalletBatch& batch, const CScript& script);
|
||||
|
||||
//! Unsets a wallet flag and saves it to disk
|
||||
void UnsetWalletFlagWithDB(WalletBatch& batch, uint64_t flag);
|
||||
void UnsetWalletFlagWithDB(WalletBatch& batch, uint64_t flag) override;
|
||||
|
||||
/** Interface for accessing chain state. */
|
||||
interfaces::Chain* m_chain;
|
||||
|
|
@ -970,9 +773,6 @@ private:
|
|||
*/
|
||||
uint256 m_last_block_processed GUARDED_BY(cs_wallet);
|
||||
|
||||
//! Fetches a key from the keypool
|
||||
bool GetKeyFromPool(CPubKey &key, bool internal = false);
|
||||
|
||||
public:
|
||||
/*
|
||||
* Main wallet lock.
|
||||
|
|
@ -987,6 +787,7 @@ public:
|
|||
{
|
||||
return *database;
|
||||
}
|
||||
WalletDatabase& GetDatabase() override { return *database; }
|
||||
|
||||
/**
|
||||
* Select a set of coins such that nValueRet >= nTargetValue and at least
|
||||
|
|
@ -1002,15 +803,6 @@ public:
|
|||
*/
|
||||
const std::string& GetName() const { return m_location.GetName(); }
|
||||
|
||||
void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
void MarkPreSplitKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
||||
// Map from Key ID to key metadata.
|
||||
std::map<CKeyID, CKeyMetadata> mapKeyMetadata GUARDED_BY(cs_wallet);
|
||||
|
||||
// Map from Script ID to key metadata (for watch-only keys).
|
||||
std::map<CScriptID, CKeyMetadata> m_script_metadata GUARDED_BY(cs_wallet);
|
||||
|
||||
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
|
||||
MasterKeyMap mapMasterKeys;
|
||||
unsigned int nMasterKeyMaxID = 0;
|
||||
|
|
@ -1034,7 +826,7 @@ public:
|
|||
}
|
||||
|
||||
bool IsCrypted() const { return fUseCrypto; }
|
||||
bool IsLocked() const;
|
||||
bool IsLocked() const override;
|
||||
bool Lock();
|
||||
|
||||
/** Interface to assert chain access and if successful lock it */
|
||||
|
|
@ -1085,7 +877,7 @@ public:
|
|||
const CWalletTx* GetWalletTx(const uint256& hash) const;
|
||||
|
||||
//! check whether we are allowed to upgrade (or already support) to the named feature
|
||||
bool CanSupportFeature(enum WalletFeature wf) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; }
|
||||
bool CanSupportFeature(enum WalletFeature wf) const override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; }
|
||||
|
||||
/**
|
||||
* populate vCoins with vector of available COutputs.
|
||||
|
|
@ -1135,34 +927,10 @@ public:
|
|||
int64_t ScanningDuration() const { return fScanningWallet ? GetTimeMillis() - m_scanning_start : 0; }
|
||||
double ScanningProgress() const { return fScanningWallet ? (double) m_scanning_progress : 0; }
|
||||
|
||||
/**
|
||||
* keystore implementation
|
||||
* Generate a new key
|
||||
*/
|
||||
CPubKey GenerateNewKey(WalletBatch& batch, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
//! 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 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);
|
||||
//! Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo
|
||||
void UpgradeKeyMetadata() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
||||
bool LoadMinVersion(int nVersion) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }
|
||||
void UpdateTimeFirstKey(int64_t nCreateTime) 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);
|
||||
//! 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 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 LoadCScript(const CScript& redeemScript);
|
||||
|
||||
//! Adds a destination data tuple to the store, and saves it to disk
|
||||
bool AddDestData(const CTxDestination& dest, const std::string& key, const std::string& value) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
|
@ -1175,18 +943,6 @@ public:
|
|||
//! Get all destination values matching a prefix.
|
||||
std::vector<std::string> GetDestValues(const std::string& prefix) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
||||
//! 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 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;
|
||||
|
||||
//! 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;
|
||||
|
||||
|
|
@ -1303,33 +1059,10 @@ public:
|
|||
/** Absolute maximum transaction fee (in satoshis) used by default for the wallet */
|
||||
CAmount m_default_max_tx_fee{DEFAULT_TRANSACTION_MAXFEE};
|
||||
|
||||
bool NewKeyPool();
|
||||
size_t KeypoolCountExternalKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
bool TopUpKeyPool(unsigned int kpSize = 0);
|
||||
|
||||
/**
|
||||
* Reserves a key from the keypool and sets nIndex to its index
|
||||
*
|
||||
* @param[out] nIndex the index of the key in keypool
|
||||
* @param[out] keypool the keypool the key was drawn from, which could be the
|
||||
* the pre-split pool if present, or the internal or external pool
|
||||
* @param fRequestedInternal true if the caller would like the key drawn
|
||||
* from the internal keypool, false if external is preferred
|
||||
*
|
||||
* @return true if succeeded, false if failed due to empty keypool
|
||||
* @throws std::runtime_error if keypool read failed, key was invalid,
|
||||
* was not found in the wallet, or was misclassified in the internal
|
||||
* or external keypool
|
||||
*/
|
||||
bool ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal);
|
||||
void KeepKey(int64_t nIndex);
|
||||
void ReturnKey(int64_t nIndex, bool fInternal, const CPubKey& pubkey);
|
||||
int64_t GetOldestKeyPoolTime();
|
||||
/**
|
||||
* Marks all keys in the keypool up to and including reserve_key as used.
|
||||
*/
|
||||
void MarkReserveKeysAsUsed(int64_t keypool_id) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
const std::map<CKeyID, int64_t>& GetAllReserveKeys() const { return m_pool_key_to_index; }
|
||||
|
||||
std::set<std::set<CTxDestination>> GetAddressGroupings() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
std::map<CTxDestination, CAmount> GetAddressBalances(interfaces::Chain::Lock& locked_chain);
|
||||
|
|
@ -1340,6 +1073,8 @@ public:
|
|||
bool GetNewDestination(const OutputType type, const std::string label, CTxDestination& dest, std::string& error, bool add_blinding_key = false);
|
||||
bool GetNewChangeDestination(const OutputType type, CTxDestination& dest, std::string& error, bool add_blinding_key = false);
|
||||
|
||||
isminetype IsMine(const CTxDestination& dest) const;
|
||||
isminetype IsMine(const CScript& script) const;
|
||||
isminetype IsMine(const CTxIn& txin) const;
|
||||
/**
|
||||
* Returns amount of debit if the input matches the
|
||||
|
|
@ -1380,7 +1115,7 @@ public:
|
|||
}
|
||||
|
||||
//! signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVersion if those are lower
|
||||
void SetMinVersion(enum WalletFeature, WalletBatch* batch_in = nullptr, bool fExplicit = false);
|
||||
void SetMinVersion(enum WalletFeature, WalletBatch* batch_in = nullptr, bool fExplicit = false) override;
|
||||
|
||||
//! change which version we're allowed to upgrade to (note that this does not immediately imply upgrading to that format)
|
||||
bool SetMaxVersion(int nVersion);
|
||||
|
|
@ -1459,31 +1194,12 @@ public:
|
|||
|
||||
bool BackupWallet(const std::string& strDest);
|
||||
|
||||
/* Set the HD chain model (chain child index counters) */
|
||||
void SetHDChain(const CHDChain& chain, bool memonly);
|
||||
const CHDChain& GetHDChain() const { return hdChain; }
|
||||
|
||||
/* Returns true if HD is enabled */
|
||||
bool IsHDEnabled() const;
|
||||
|
||||
/* Returns true if the wallet can generate new keys */
|
||||
bool CanGenerateKeys();
|
||||
|
||||
/* Returns true if the wallet can give out new addresses. This means it has keys in the keypool or can generate new keys */
|
||||
bool CanGetAddresses(bool internal = false);
|
||||
|
||||
/* Generates a new HD seed (will not be activated) */
|
||||
CPubKey GenerateNewSeed();
|
||||
|
||||
/* Derives a new HD seed (will not be activated) */
|
||||
CPubKey DeriveNewSeed(const CKey& key);
|
||||
|
||||
/* Set the current HD seed (will reset the chain child index counters)
|
||||
Sets the seed's version based on the current wallet version (so the
|
||||
caller must ensure the current wallet version is correct before calling
|
||||
this function). */
|
||||
void SetHDSeed(const CPubKey& key);
|
||||
|
||||
/**
|
||||
* Blocks until the wallet state is up-to-date to /at least/ the current
|
||||
* chain at the time this function is entered
|
||||
|
|
@ -1492,35 +1208,21 @@ public:
|
|||
*/
|
||||
void BlockUntilSyncedToCurrentChain() LOCKS_EXCLUDED(cs_main, cs_wallet);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* software, as FillableSigningProvider automatically does this implicitly for all
|
||||
* keys now.
|
||||
*/
|
||||
void LearnRelatedScripts(const CPubKey& key, OutputType);
|
||||
|
||||
/**
|
||||
* Same as LearnRelatedScripts, but when the OutputType is not known (and could
|
||||
* be anything).
|
||||
*/
|
||||
void LearnAllRelatedScripts(const CPubKey& key);
|
||||
|
||||
/** set a single wallet flag */
|
||||
void SetWalletFlag(uint64_t flags);
|
||||
void SetWalletFlag(uint64_t flags) override;
|
||||
|
||||
/** Unsets a single wallet flag */
|
||||
void UnsetWalletFlag(uint64_t flag);
|
||||
|
||||
/** check if a certain wallet flag is set */
|
||||
bool IsWalletFlagSet(uint64_t flag) const;
|
||||
bool IsWalletFlagSet(uint64_t flag) const override;
|
||||
|
||||
/** overwrite all flags by the given uint64_t
|
||||
returns false if unknown, non-tolerable flags are present */
|
||||
bool SetWalletFlags(uint64_t overwriteFlags, bool memOnly);
|
||||
|
||||
/** Returns a bracketed wallet name for displaying in logs, will return [default wallet] if the wallet has no name */
|
||||
const std::string GetDisplayName() const {
|
||||
const std::string GetDisplayName() const override {
|
||||
std::string wallet_name = GetName().length() == 0 ? "default wallet" : GetName();
|
||||
return strprintf("[%s]", wallet_name);
|
||||
};
|
||||
|
|
@ -1531,8 +1233,28 @@ public:
|
|||
LogPrintf(("%s " + fmt).c_str(), GetDisplayName(), parameters...);
|
||||
};
|
||||
|
||||
/** Implement lookup of key origin information through wallet key metadata. */
|
||||
bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
|
||||
ScriptPubKeyMan* GetScriptPubKeyMan() const;
|
||||
const SigningProvider* GetSigningProvider() const;
|
||||
LegacyScriptPubKeyMan* GetLegacyScriptPubKeyMan() const;
|
||||
|
||||
// Temporary LegacyScriptPubKeyMan accessors and aliases.
|
||||
friend class LegacyScriptPubKeyMan;
|
||||
std::unique_ptr<LegacyScriptPubKeyMan> m_spk_man = MakeUnique<LegacyScriptPubKeyMan>(*this);
|
||||
CCriticalSection& cs_KeyStore = m_spk_man->cs_KeyStore;
|
||||
LegacyScriptPubKeyMan::KeyMap& mapKeys GUARDED_BY(cs_KeyStore) = m_spk_man->mapKeys;
|
||||
LegacyScriptPubKeyMan::ScriptMap& mapScripts GUARDED_BY(cs_KeyStore) = m_spk_man->mapScripts;
|
||||
LegacyScriptPubKeyMan::CryptedKeyMap& mapCryptedKeys GUARDED_BY(cs_KeyStore) = m_spk_man->mapCryptedKeys;
|
||||
LegacyScriptPubKeyMan::WatchOnlySet& setWatchOnly GUARDED_BY(cs_KeyStore) = m_spk_man->setWatchOnly;
|
||||
LegacyScriptPubKeyMan::WatchKeyMap& mapWatchKeys GUARDED_BY(cs_KeyStore) = m_spk_man->mapWatchKeys;
|
||||
WalletBatch*& encrypted_batch GUARDED_BY(cs_wallet) = m_spk_man->encrypted_batch;
|
||||
std::set<int64_t>& setInternalKeyPool GUARDED_BY(cs_wallet) = m_spk_man->setInternalKeyPool;
|
||||
std::set<int64_t>& setExternalKeyPool GUARDED_BY(cs_wallet) = m_spk_man->setExternalKeyPool;
|
||||
int64_t& nTimeFirstKey GUARDED_BY(cs_wallet) = m_spk_man->nTimeFirstKey;
|
||||
std::map<CKeyID, CKeyMetadata>& mapKeyMetadata GUARDED_BY(cs_wallet) = m_spk_man->mapKeyMetadata;
|
||||
std::map<CScriptID, CKeyMetadata>& m_script_metadata GUARDED_BY(cs_wallet) = m_spk_man->m_script_metadata;
|
||||
void MarkPreSplitKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(m_spk_man->cs_wallet); m_spk_man->MarkPreSplitKeys(); }
|
||||
void MarkReserveKeysAsUsed(int64_t keypool_id) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(m_spk_man->cs_wallet); m_spk_man->MarkReserveKeysAsUsed(keypool_id); }
|
||||
using CryptedKeyMap = LegacyScriptPubKeyMan::CryptedKeyMap;
|
||||
|
||||
//
|
||||
// ELEMENTS
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ public:
|
|||
|
||||
static bool
|
||||
ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||
CWalletScanState &wss, std::string& strType, std::string& strErr) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
|
||||
CWalletScanState &wss, std::string& strType, std::string& strErr) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet, pwallet->GetLegacyScriptPubKeyMan()->cs_wallet)
|
||||
{
|
||||
try {
|
||||
// Unserialize
|
||||
|
|
@ -281,8 +281,9 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
|||
ssKey >> script;
|
||||
char fYes;
|
||||
ssValue >> fYes;
|
||||
if (fYes == '1')
|
||||
pwallet->LoadWatchOnly(script);
|
||||
if (fYes == '1') {
|
||||
pwallet->GetLegacyScriptPubKeyMan()->LoadWatchOnly(script);
|
||||
}
|
||||
} else if (strType == DBKeys::KEY) {
|
||||
CPubKey vchPubKey;
|
||||
ssKey >> vchPubKey;
|
||||
|
|
@ -333,12 +334,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
|||
strErr = "Error reading wallet database: CPrivKey corrupt";
|
||||
return false;
|
||||
}
|
||||
if (!pwallet->LoadKey(key, vchPubKey))
|
||||
if (!pwallet->GetLegacyScriptPubKeyMan()->LoadKey(key, vchPubKey))
|
||||
{
|
||||
strErr = "Error reading wallet database: LoadKey failed";
|
||||
strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadKey failed";
|
||||
return false;
|
||||
}
|
||||
} else if (strType == DBKeys::MASTER_KEY) {
|
||||
// Master encryption key is loaded into only the wallet and not any of the ScriptPubKeyMans.
|
||||
unsigned int nID;
|
||||
ssKey >> nID;
|
||||
CMasterKey kMasterKey;
|
||||
|
|
@ -363,9 +365,9 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
|||
ssValue >> vchPrivKey;
|
||||
wss.nCKeys++;
|
||||
|
||||
if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
|
||||
if (!pwallet->GetLegacyScriptPubKeyMan()->LoadCryptedKey(vchPubKey, vchPrivKey))
|
||||
{
|
||||
strErr = "Error reading wallet database: LoadCryptedKey failed";
|
||||
strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadCryptedKey failed";
|
||||
return false;
|
||||
}
|
||||
wss.fIsEncrypted = true;
|
||||
|
|
@ -375,14 +377,14 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
|||
CKeyMetadata keyMeta;
|
||||
ssValue >> keyMeta;
|
||||
wss.nKeyMeta++;
|
||||
pwallet->LoadKeyMetadata(vchPubKey.GetID(), keyMeta);
|
||||
pwallet->GetLegacyScriptPubKeyMan()->LoadKeyMetadata(vchPubKey.GetID(), keyMeta);
|
||||
} else if (strType == DBKeys::WATCHMETA) {
|
||||
CScript script;
|
||||
ssKey >> script;
|
||||
CKeyMetadata keyMeta;
|
||||
ssValue >> keyMeta;
|
||||
wss.nKeyMeta++;
|
||||
pwallet->LoadScriptMetadata(CScriptID(script), keyMeta);
|
||||
pwallet->GetLegacyScriptPubKeyMan()->LoadScriptMetadata(CScriptID(script), keyMeta);
|
||||
} else if (strType == DBKeys::DEFAULTKEY) {
|
||||
// We don't want or need the default key, but if there is one set,
|
||||
// we want to make sure that it is valid so that we can detect corruption
|
||||
|
|
@ -398,15 +400,15 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
|||
CKeyPool keypool;
|
||||
ssValue >> keypool;
|
||||
|
||||
pwallet->LoadKeyPool(nIndex, keypool);
|
||||
pwallet->GetLegacyScriptPubKeyMan()->LoadKeyPool(nIndex, keypool);
|
||||
} else if (strType == DBKeys::CSCRIPT) {
|
||||
uint160 hash;
|
||||
ssKey >> hash;
|
||||
CScript script;
|
||||
ssValue >> script;
|
||||
if (!pwallet->LoadCScript(script))
|
||||
if (!pwallet->GetLegacyScriptPubKeyMan()->LoadCScript(script))
|
||||
{
|
||||
strErr = "Error reading wallet database: LoadCScript failed";
|
||||
strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadCScript failed";
|
||||
return false;
|
||||
}
|
||||
} else if (strType == DBKeys::ORDERPOSNEXT) {
|
||||
|
|
@ -420,7 +422,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
|||
} else if (strType == DBKeys::HDCHAIN) {
|
||||
CHDChain chain;
|
||||
ssValue >> chain;
|
||||
pwallet->SetHDChain(chain, true);
|
||||
pwallet->GetLegacyScriptPubKeyMan()->SetHDChain(chain, true);
|
||||
} else if (strType == DBKeys::FLAGS) {
|
||||
uint64_t flags;
|
||||
ssValue >> flags;
|
||||
|
|
@ -507,6 +509,7 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
|
|||
DBErrors result = DBErrors::LOAD_OK;
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
AssertLockHeld(pwallet->GetLegacyScriptPubKeyMan()->cs_wallet);
|
||||
try {
|
||||
int nMinVersion = 0;
|
||||
if (m_batch.Read(DBKeys::MINVERSION, nMinVersion)) {
|
||||
|
|
@ -597,8 +600,12 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
|
|||
wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys, wss.m_unknown_records);
|
||||
|
||||
// nTimeFirstKey is only reliable if all keys have metadata
|
||||
if ((wss.nKeys + wss.nCKeys + wss.nWatchKeys) != wss.nKeyMeta)
|
||||
pwallet->UpdateTimeFirstKey(1);
|
||||
if ((wss.nKeys + wss.nCKeys + wss.nWatchKeys) != wss.nKeyMeta) {
|
||||
auto spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (spk_man) {
|
||||
spk_man->UpdateTimeFirstKey(1);
|
||||
}
|
||||
}
|
||||
|
||||
for (const uint256& hash : wss.vWalletUpgrade)
|
||||
WriteTx(pwallet->mapWallet.at(hash));
|
||||
|
|
@ -791,6 +798,7 @@ bool WalletBatch::RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, C
|
|||
{
|
||||
// Required in LoadKeyMetadata():
|
||||
LOCK(dummyWallet->cs_wallet);
|
||||
AssertLockHeld(dummyWallet->GetLegacyScriptPubKeyMan()->cs_wallet);
|
||||
fReadOK = ReadKeyValue(dummyWallet, ssKey, ssValue,
|
||||
dummyWss, strType, strErr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,8 +37,9 @@ static std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::
|
|||
wallet_instance->SetMinVersion(FEATURE_HD_SPLIT);
|
||||
|
||||
// generate a new HD seed
|
||||
CPubKey seed = wallet_instance->GenerateNewSeed();
|
||||
wallet_instance->SetHDSeed(seed);
|
||||
auto spk_man = wallet_instance->GetLegacyScriptPubKeyMan();
|
||||
CPubKey seed = spk_man->GenerateNewSeed();
|
||||
spk_man->SetHDSeed(seed);
|
||||
|
||||
tfm::format(std::cout, "Topping up keypool...\n");
|
||||
wallet_instance->TopUpKeyPool();
|
||||
|
|
@ -94,7 +95,7 @@ static void WalletShowInfo(CWallet* wallet_instance)
|
|||
|
||||
tfm::format(std::cout, "Wallet info\n===========\n");
|
||||
tfm::format(std::cout, "Encrypted: %s\n", wallet_instance->IsCrypted() ? "yes" : "no");
|
||||
tfm::format(std::cout, "HD (hd seed available): %s\n", wallet_instance->GetHDChain().seed_id.IsNull() ? "no" : "yes");
|
||||
tfm::format(std::cout, "HD (hd seed available): %s\n", wallet_instance->IsHDEnabled() ? "yes" : "no");
|
||||
tfm::format(std::cout, "Keypool Size: %u\n", wallet_instance->GetKeyPoolSize());
|
||||
tfm::format(std::cout, "Transactions: %zu\n", wallet_instance->mapWallet.size());
|
||||
tfm::format(std::cout, "Address Book: %zu\n", wallet_instance->mapAddressBook.size());
|
||||
|
|
|
|||
|
|
@ -9,6 +9,54 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
/** (client) version numbers for particular wallet features */
|
||||
enum WalletFeature
|
||||
{
|
||||
FEATURE_BASE = 10500, // the earliest version new wallets supports (only useful for getwalletinfo's clientversion output)
|
||||
|
||||
FEATURE_WALLETCRYPT = 40000, // wallet encryption
|
||||
FEATURE_COMPRPUBKEY = 60000, // compressed public keys
|
||||
|
||||
FEATURE_HD = 130000, // Hierarchical key derivation after BIP32 (HD Wallet)
|
||||
|
||||
FEATURE_HD_SPLIT = 139900, // Wallet with HD chain split (change outputs will use m/0'/1'/k)
|
||||
|
||||
FEATURE_NO_DEFAULT_KEY = 159900, // Wallet without a default key written
|
||||
|
||||
FEATURE_PRE_SPLIT_KEYPOOL = 169900, // Upgraded to HD SPLIT and can have a pre-split keypool
|
||||
|
||||
FEATURE_LATEST = FEATURE_PRE_SPLIT_KEYPOOL
|
||||
};
|
||||
|
||||
|
||||
|
||||
enum WalletFlags : uint64_t {
|
||||
// wallet flags in the upper section (> 1 << 31) will lead to not opening the wallet if flag is unknown
|
||||
// unknown wallet flags in the lower section <= (1 << 31) will be tolerated
|
||||
|
||||
// will categorize coins as clean (not reused) and dirty (reused), and handle
|
||||
// them with privacy considerations in mind
|
||||
WALLET_FLAG_AVOID_REUSE = (1ULL << 0),
|
||||
|
||||
// Indicates that the metadata has already been upgraded to contain key origins
|
||||
WALLET_FLAG_KEY_ORIGIN_METADATA = (1ULL << 1),
|
||||
|
||||
// will enforce the rule that the wallet can't contain any private keys (only watch-only/pubkeys)
|
||||
WALLET_FLAG_DISABLE_PRIVATE_KEYS = (1ULL << 32),
|
||||
|
||||
//! Flag set when a wallet contains no HD seed and no private keys, scripts,
|
||||
//! addresses, and other watch only things, and is therefore "blank."
|
||||
//!
|
||||
//! The only function this flag serves is to distinguish a blank wallet from
|
||||
//! a newly created wallet when the wallet database is loaded, to avoid
|
||||
//! initialization that should only happen on first run.
|
||||
//!
|
||||
//! This flag is also a mandatory flag to prevent previous versions of
|
||||
//! bitcoin from opening the wallet, thinking it was newly created, and
|
||||
//! then improperly reinitializing it.
|
||||
WALLET_FLAG_BLANK_WALLET = (1ULL << 33),
|
||||
};
|
||||
|
||||
//! Get the path of the wallet directory.
|
||||
fs::path GetWalletDir();
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ EXPECTED_CIRCULAR_DEPENDENCIES=(
|
|||
"qt/guiutil -> qt/walletmodel -> qt/optionsmodel -> qt/guiutil"
|
||||
"txmempool -> validation -> validationinterface -> txmempool"
|
||||
"wallet/coinselection -> wallet/wallet -> wallet/coinselection"
|
||||
"wallet/ismine -> wallet/wallet -> wallet/ismine"
|
||||
"wallet/scriptpubkeyman -> wallet/wallet -> wallet/scriptpubkeyman"
|
||||
)
|
||||
|
||||
EXIT_CODE=0
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ FALSE_POSITIVES = [
|
|||
("src/wallet/wallet.h", "WalletLogPrintf(std::string fmt, Params... parameters)"),
|
||||
("src/wallet/wallet.h", "LogPrintf((\"%s \" + fmt).c_str(), GetDisplayName(), parameters...)"),
|
||||
("src/logging.h", "LogPrintf(const char* fmt, const Args&... args)"),
|
||||
("src/wallet/scriptpubkeyman.h", "WalletLogPrintf(const std::string& fmt, const Params&... parameters)"),
|
||||
("src/wallet/scriptpubkeyman.cpp", "WalletLogPrintf(fmt, parameters...)"),
|
||||
("src/wallet/scriptpubkeyman.cpp", "WalletLogPrintf(const std::string& fmt, const Params&... parameters)"),
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
export LC_ALL=C
|
||||
UNTERMINATED_LOGS=$(git grep --extended-regexp "LogPrintf?\(" -- "*.cpp" | \
|
||||
grep -v '\\n"' | \
|
||||
grep -v '\.\.\.' | \
|
||||
grep -v "/\* Continued \*/" | \
|
||||
grep -v "LogPrint()" | \
|
||||
grep -v "LogPrintf()")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue