mirror of
https://github.com/dashpay/dash.git
synced 2024-12-24 19:42:46 +01:00
* Move wallet enums to walletutil.h * MOVEONLY: Move key handling code out of wallet to keyman file Start moving wallet and ismine code to scriptpubkeyman.h, scriptpubkeyman.cpp The easiest way to review this commit is to run: git log -p -n1 --color-moved=dimmed_zebra And check that everything is a move (other than includes and copyrights comments). This commit is move-only and doesn't change code or affect behavior. * Refactor: Split up CWallet and LegacyScriptPubKeyMan and classes This moves CWallet members and methods dealing with keys to a new LegacyScriptPubKeyMan class, and updates calling code to reference the new class instead of CWallet. Most of the changes are simple text replacements and variable substitutions easily verified with: git log -p -n1 -U0 --word-diff-regex=. The only nontrivial chunk of code added is the new LegacyScriptPubKeyMan class declaration, but this code isn't new and is just selectively copied and moved from the previous CWallet class declaration. This can be verified with: git log -p -n1 --color-moved=dimmed_zebra src/wallet/scriptpubkeyman.h src/wallet/wallet.h or git diff HEAD~1:src/wallet/wallet.h HEAD:src/wallet/scriptpubkeyman.h This commit does not change behavior. * Renamed classes in scriptpubkeyman * Fixes for conflicts, compilation and linkage errors due to previous commits * Reordered methods in scriptpubkeyman to make further backports easier * Reordered methods in scriptpubkeyman to make further backports easier (part II) * Remove HDChain copy from SigningProvider class * fixes/suggestions Co-authored-by: Andrew Chow <achow101-github@achow101.com> Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
This commit is contained in:
parent
8882a7377e
commit
ae051bb6e0
@ -330,6 +330,7 @@ BITCOIN_CORE_H = \
|
||||
wallet/psbtwallet.h \
|
||||
wallet/rpcwallet.h \
|
||||
wallet/salvage.h \
|
||||
wallet/scriptpubkeyman.h \
|
||||
wallet/wallet.h \
|
||||
wallet/walletdb.h \
|
||||
wallet/wallettool.h \
|
||||
@ -489,12 +490,12 @@ libdash_wallet_a_SOURCES = \
|
||||
wallet/crypter.cpp \
|
||||
wallet/db.cpp \
|
||||
wallet/fees.cpp \
|
||||
wallet/ismine.cpp \
|
||||
wallet/load.cpp \
|
||||
wallet/psbtwallet.cpp \
|
||||
wallet/rpcdump.cpp \
|
||||
wallet/rpcwallet.cpp \
|
||||
wallet/salvage.cpp \
|
||||
wallet/scriptpubkeyman.cpp \
|
||||
wallet/wallet.cpp \
|
||||
wallet/walletdb.cpp \
|
||||
wallet/walletutil.cpp \
|
||||
|
@ -602,7 +602,7 @@ bool CCoinJoinClientSession::SignFinalTransaction(const CTransaction& finalTrans
|
||||
|
||||
LogPrint(BCLog::COINJOIN, "CCoinJoinClientSession::%s -- Signing my input %i\n", __func__, nMyInputIndex);
|
||||
// TODO we're using amount=0 here but we should use the correct amount. This works because Dash ignores the amount while signing/verifying (only used in Bitcoin/Segwit)
|
||||
if (!SignSignature(mixingWallet, prevPubKey, finalMutableTransaction, nMyInputIndex, 0, int(SIGHASH_ALL | SIGHASH_ANYONECANPAY))) { // changes scriptSig
|
||||
if (!SignSignature(*mixingWallet.GetSigningProvider(), prevPubKey, finalMutableTransaction, nMyInputIndex, 0, int(SIGHASH_ALL | SIGHASH_ANYONECANPAY))) { // changes scriptSig
|
||||
LogPrint(BCLog::COINJOIN, "CCoinJoinClientSession::%s -- Unable to sign my own transaction!\n", __func__);
|
||||
// not sure what to do here, it will time out...?
|
||||
}
|
||||
@ -1522,7 +1522,7 @@ bool CCoinJoinClientSession::CreateCollateralTransaction(CMutableTransaction& tx
|
||||
txCollateral.vout.emplace_back(0, CScript() << OP_RETURN);
|
||||
}
|
||||
|
||||
if (!SignSignature(mixingWallet, txout.scriptPubKey, txCollateral, 0, txout.nValue, SIGHASH_ALL)) {
|
||||
if (!SignSignature(*mixingWallet.GetSigningProvider(), txout.scriptPubKey, txCollateral, 0, txout.nValue, SIGHASH_ALL)) {
|
||||
strReason = "Unable to sign collateral transaction!";
|
||||
return false;
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
|
||||
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);
|
||||
if (!fOutputDenomFound && result.txout_address_is_mine.back() && CCoinJoin::IsDenominatedAmount(txout.nValue)) {
|
||||
fOutputDenomFound = true;
|
||||
@ -183,13 +183,36 @@ public:
|
||||
std::string getWalletName() override { return m_wallet->GetName(); }
|
||||
bool getKeyFromPool(bool internal, CPubKey& pub_key) override
|
||||
{
|
||||
return m_wallet->GetKeyFromPool(pub_key, internal);
|
||||
auto spk_man = m_wallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
return false;
|
||||
}
|
||||
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 CScript& script) override { return IsMine(*m_wallet, script) & ISMINE_SPENDABLE; }
|
||||
bool isSpendable(const CTxDestination& dest) override { return IsMine(*m_wallet, dest) & ISMINE_SPENDABLE; }
|
||||
bool haveWatchOnly() override { return m_wallet->HaveWatchOnly(); };
|
||||
return spk_man->GetKeyFromPool(pub_key, internal);
|
||||
}
|
||||
bool getPubKey(const CKeyID& address, CPubKey& pub_key) override {
|
||||
auto spk_man = m_wallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
return false;
|
||||
}
|
||||
return spk_man->GetPubKey(address, pub_key);
|
||||
}
|
||||
bool getPrivKey(const CKeyID& address, CKey& key) override {
|
||||
auto spk_man = m_wallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
return false;
|
||||
}
|
||||
return spk_man->GetKey(address, key);
|
||||
}
|
||||
bool isSpendable(const CScript& script) override { return m_wallet->IsMine(script) & ISMINE_SPENDABLE; }
|
||||
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);
|
||||
@ -212,7 +235,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;
|
||||
@ -224,11 +247,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 { if (spk_man) 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);
|
||||
@ -380,7 +403,7 @@ public:
|
||||
result.unconfirmed_balance = bal.m_mine_untrusted_pending;
|
||||
result.immature_balance = bal.m_mine_immature;
|
||||
result.anonymized_balance = bal.m_anonymized;
|
||||
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;
|
||||
|
@ -114,9 +114,11 @@ void TestGUI(interfaces::Node& node)
|
||||
bool firstRun;
|
||||
wallet->LoadWallet(firstRun);
|
||||
{
|
||||
auto spk_man = wallet->GetLegacyScriptPubKeyMan();
|
||||
LOCK(wallet->cs_wallet);
|
||||
AssertLockHeld(spk_man->cs_wallet);
|
||||
wallet->SetAddressBook(test.coinbaseKey.GetPubKey().GetID(), "", "receive");
|
||||
wallet->AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
|
||||
spk_man->AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
|
||||
wallet->SetLastBlockProcessed(105, ::ChainActive().Tip()->GetBlockHash());
|
||||
}
|
||||
{
|
||||
|
@ -628,12 +628,17 @@ static UniValue gobject_vote_many(const JSONRPCRequest& request)
|
||||
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
std::map<uint256, CKey> votingKeys;
|
||||
|
||||
auto mnList = deterministicMNManager->GetListAtChainTip();
|
||||
mnList.ForEachMN(true, [&](auto& dmn) {
|
||||
CKey votingKey;
|
||||
if (pwallet->GetKey(dmn.pdmnState->keyIDVoting, votingKey)) {
|
||||
if (spk_man->GetKey(dmn.pdmnState->keyIDVoting, votingKey)) {
|
||||
votingKeys.emplace(dmn.proTxHash, votingKey);
|
||||
}
|
||||
});
|
||||
@ -689,8 +694,13 @@ static UniValue gobject_vote_alias(const JSONRPCRequest& request)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid or unknown proTxHash");
|
||||
}
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
CKey votingKey;
|
||||
if (!pwallet->GetKey(dmn->pdmnState->keyIDVoting, votingKey)) {
|
||||
if (!spk_man->GetKey(dmn->pdmnState->keyIDVoting, votingKey)) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Private key for voting address %s not known by wallet", EncodeDestination(dmn->pdmnState->keyIDVoting)));
|
||||
}
|
||||
|
||||
|
@ -579,8 +579,13 @@ static UniValue protx_register(const JSONRPCRequest& request)
|
||||
return ret;
|
||||
} else {
|
||||
// lets prove we own the collateral
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
CKey key;
|
||||
if (!pwallet->GetKey(*keyID, key)) {
|
||||
if (!spk_man->GetKey(*keyID, key)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("collateral key not in wallet: %s", EncodeDestination(txDest)));
|
||||
}
|
||||
SignSpecialTxPayloadByString(tx, ptx, key);
|
||||
@ -779,8 +784,13 @@ static UniValue protx_update_registrar(const JSONRPCRequest& request)
|
||||
ptx.scriptPayout = GetScriptForDestination(payoutDest);
|
||||
}
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
CKey keyOwner;
|
||||
if (!pwallet->GetKey(dmn->pdmnState->keyIDOwner, keyOwner)) {
|
||||
if (!spk_man->GetKey(dmn->pdmnState->keyIDOwner, keyOwner)) {
|
||||
throw std::runtime_error(strprintf("Private key for owner address %s not found in your wallet", EncodeDestination(dmn->pdmnState->keyIDOwner)));
|
||||
}
|
||||
|
||||
@ -919,17 +929,25 @@ static bool CheckWalletOwnsKey(CWallet* pwallet, const CKeyID& keyID) {
|
||||
if (!pwallet) {
|
||||
return false;
|
||||
}
|
||||
return pwallet->HaveKey(keyID);
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
return false;
|
||||
}
|
||||
return spk_man->HaveKey(keyID);
|
||||
}
|
||||
|
||||
static bool CheckWalletOwnsScript(CWallet* pwallet, const CScript& script) {
|
||||
if (!pwallet) {
|
||||
return false;
|
||||
}
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CTxDestination dest;
|
||||
if (ExtractDestination(script, dest)) {
|
||||
if ((boost::get<CKeyID>(&dest) && pwallet->HaveKey(*boost::get<CKeyID>(&dest))) || (boost::get<CScriptID>(&dest) && pwallet->HaveCScript(*boost::get<CScriptID>(&dest)))) {
|
||||
if ((boost::get<CKeyID>(&dest) && spk_man->HaveKey(*boost::get<CKeyID>(&dest))) || (boost::get<CScriptID>(&dest) && spk_man->HaveCScript(*boost::get<CScriptID>(&dest)))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -150,10 +150,3 @@ bool FillableSigningProvider::GetCScript(const CScriptID &hash, CScript& redeemS
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FillableSigningProvider::GetHDChain(CHDChain& hdChainRet) const
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
hdChainRet = hdChain;
|
||||
return !hdChain.IsNull();
|
||||
}
|
||||
|
@ -64,17 +64,15 @@ 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>;
|
||||
|
||||
KeyMap mapKeys GUARDED_BY(cs_KeyStore);
|
||||
ScriptMap mapScripts GUARDED_BY(cs_KeyStore);
|
||||
/* the HD chain data model*/
|
||||
CHDChain hdChain GUARDED_BY(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;
|
||||
@ -85,8 +83,6 @@ public:
|
||||
virtual bool HaveCScript(const CScriptID &hash) const override;
|
||||
virtual std::set<CScriptID> GetCScripts() const;
|
||||
virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const override;
|
||||
|
||||
virtual bool GetHDChain(CHDChain& hdChainRet) const;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_SCRIPT_SIGNINGPROVIDER_H
|
||||
|
@ -23,8 +23,11 @@ const std::string ADDRESS_BCRT1_UNSPENDABLE = "bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqq
|
||||
#ifdef ENABLE_WALLET
|
||||
std::string getnewaddress(CWallet& w)
|
||||
{
|
||||
auto spk_man = w.GetLegacyScriptPubKeyMan();
|
||||
assert(spk_man != nullptr);
|
||||
|
||||
CPubKey new_key;
|
||||
if (!w.GetKeyFromPool(new_key, false)) assert(false);
|
||||
if (!spk_man->GetKeyFromPool(new_key, false)) assert(false);
|
||||
|
||||
CKeyID keyID = new_key.GetID();
|
||||
w.SetAddressBook(keyID, /* label */ "", "receive");
|
||||
@ -34,13 +37,16 @@ std::string getnewaddress(CWallet& w)
|
||||
|
||||
void importaddress(CWallet& wallet, const std::string& address)
|
||||
{
|
||||
auto spk_man = wallet.GetLegacyScriptPubKeyMan();
|
||||
assert(spk_man != nullptr);
|
||||
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
|
||||
|
@ -7,8 +7,8 @@
|
||||
|
||||
#include <tinyformat.h>
|
||||
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
/**
|
||||
* Bilingual messages:
|
||||
|
@ -1,156 +0,0 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2015 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <wallet/ismine.h>
|
||||
|
||||
#include <key.h>
|
||||
#include <script/script.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <wallet/wallet.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
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 (P2SH inside P2SH)
|
||||
};
|
||||
|
||||
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:
|
||||
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_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 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_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;
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
|
@ -27,12 +27,12 @@ TransactionError FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& ps
|
||||
return TransactionError::SIGHASH_MISMATCH;
|
||||
}
|
||||
|
||||
complete &= SignPSBTInput(HidingSigningProvider(pwallet, !sign, !bip32derivs), *psbtx.tx, input, i, sighash_type);
|
||||
complete &= SignPSBTInput(HidingSigningProvider(pwallet->GetSigningProvider(), !sign, !bip32derivs), *psbtx.tx, input, i, sighash_type);
|
||||
}
|
||||
|
||||
// Fill in the bip32 keypaths and redeemscripts for the outputs so that hardware wallets can identify change
|
||||
for (unsigned int i = 0; i < psbtx.tx->vout.size(); ++i) {
|
||||
UpdatePSBTOutput(HidingSigningProvider(pwallet, true, !bip32derivs), psbtx, i);
|
||||
UpdatePSBTOutput(HidingSigningProvider(pwallet->GetSigningProvider(), true, !bip32derivs), psbtx, i);
|
||||
}
|
||||
|
||||
return TransactionError::OK;
|
||||
|
@ -103,11 +103,17 @@ 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");
|
||||
}
|
||||
|
||||
WalletBatch batch(pwallet->GetDBHandle());
|
||||
WalletRescanReserver reserver(pwallet);
|
||||
bool fRescan = true;
|
||||
{
|
||||
LOCK(pwallet->cs_wallet);
|
||||
AssertLockHeld(spk_man->cs_wallet);
|
||||
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
|
||||
@ -145,17 +151,17 @@ UniValue importprivkey(const JSONRPCRequest& request)
|
||||
}
|
||||
|
||||
// Don't throw error in case a key is already there
|
||||
if (pwallet->HaveKey(vchAddress)) {
|
||||
if (spk_man->HaveKey(vchAddress)) {
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
// whenever a key is imported, we need to scan the whole chain
|
||||
pwallet->UpdateTimeFirstKey(1);
|
||||
pwallet->mapKeyMetadata[vchAddress].nCreateTime = 1;
|
||||
|
||||
if (!pwallet->AddKeyPubKeyWithDB(batch, key, pubkey)) {
|
||||
spk_man->UpdateTimeFirstKey(1);
|
||||
spk_man->mapKeyMetadata[vchAddress].nCreateTime = 1;
|
||||
if (!spk_man->AddKeyPubKeyWithDB(batch, key, pubkey)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (fRescan) {
|
||||
@ -194,19 +200,26 @@ static void ImportScript(CWallet * const pwallet, const CScript& script, const s
|
||||
{
|
||||
WalletBatch batch(pwallet->GetDBHandle());
|
||||
|
||||
if (!isRedeemScript && ::IsMine(*pwallet, script) == ISMINE_SPENDABLE) {
|
||||
if (!isRedeemScript && pwallet->IsMine(script) == ISMINE_SPENDABLE) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
|
||||
}
|
||||
|
||||
pwallet->MarkDirty();
|
||||
|
||||
if (!pwallet->HaveWatchOnly(script) && !pwallet->AddWatchOnlyWithDB(batch, script, 0 /* nCreateTime */)) {
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
AssertLockHeld(spk_man->cs_wallet);
|
||||
|
||||
if (!spk_man->HaveWatchOnly(script) && !spk_man->AddWatchOnlyWithDB(batch, script, 0 /* nCreateTime */)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
|
||||
}
|
||||
|
||||
if (isRedeemScript) {
|
||||
const CScriptID id(script);
|
||||
if (!pwallet->HaveCScript(id) && !pwallet->AddCScriptWithDB(batch, script)) {
|
||||
if (!spk_man->HaveCScript(id) && !spk_man->AddCScriptWithDB(batch, script)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
|
||||
}
|
||||
ImportAddress(pwallet, id, strLabel);
|
||||
@ -585,6 +598,13 @@ UniValue importwallet(const JSONRPCRequest& request)
|
||||
}
|
||||
double total = (double)(keys.size() + scripts.size());
|
||||
double progress = 0;
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (spk_man == nullptr) {
|
||||
if (total > 0) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
} else {
|
||||
AssertLockHeld(spk_man->cs_wallet);
|
||||
for (const auto& key_tuple : keys) {
|
||||
pwallet->chain().showProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false);
|
||||
const CKey& key = std::get<0>(key_tuple);
|
||||
@ -595,16 +615,16 @@ UniValue importwallet(const JSONRPCRequest& request)
|
||||
CPubKey pubkey = key.GetPubKey();
|
||||
CHECK_NONFATAL(key.VerifyPubKey(pubkey));
|
||||
CKeyID keyid = pubkey.GetID();
|
||||
if (pwallet->HaveKey(keyid)) {
|
||||
if (spk_man->HaveKey(keyid)) {
|
||||
pwallet->WalletLogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid));
|
||||
continue;
|
||||
}
|
||||
pwallet->WalletLogPrintf("Importing %s...\n", EncodeDestination(keyid));
|
||||
if (!pwallet->AddKeyPubKeyWithDB(batch, key, pubkey)) {
|
||||
if (!spk_man->AddKeyPubKeyWithDB(batch, key, pubkey)) {
|
||||
fGood = false;
|
||||
continue;
|
||||
}
|
||||
pwallet->mapKeyMetadata[keyid].nCreateTime = time;
|
||||
spk_man->mapKeyMetadata[keyid].nCreateTime = time;
|
||||
if (has_label)
|
||||
pwallet->SetAddressBook(keyid, label, "receive");
|
||||
nTimeBegin = std::min(nTimeBegin, time);
|
||||
@ -615,23 +635,24 @@ UniValue importwallet(const JSONRPCRequest& request)
|
||||
const CScript& script = script_pair.first;
|
||||
int64_t time = script_pair.second;
|
||||
CScriptID id(script);
|
||||
if (pwallet->HaveCScript(id)) {
|
||||
if (spk_man->HaveCScript(id)) {
|
||||
pwallet->WalletLogPrintf("Skipping import of %s (script already present)\n", HexStr(script));
|
||||
continue;
|
||||
}
|
||||
if(!pwallet->AddCScriptWithDB(batch, script)) {
|
||||
if(!spk_man->AddCScriptWithDB(batch, script)) {
|
||||
pwallet->WalletLogPrintf("Error importing script %s\n", HexStr(script));
|
||||
fGood = false;
|
||||
continue;
|
||||
}
|
||||
if (time > 0) {
|
||||
pwallet->m_script_metadata[id].nCreateTime = time;
|
||||
spk_man->m_script_metadata[id].nCreateTime = time;
|
||||
nTimeBegin = std::min(nTimeBegin, time);
|
||||
}
|
||||
progress++;
|
||||
}
|
||||
pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
|
||||
pwallet->UpdateTimeFirstKey(nTimeBegin);
|
||||
spk_man->UpdateTimeFirstKey(nTimeBegin);
|
||||
}
|
||||
}
|
||||
pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
|
||||
RescanWallet(*pwallet, reserver, nTimeBegin, false /* update */);
|
||||
@ -673,7 +694,13 @@ UniValue importelectrumwallet(const JSONRPCRequest& request)
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
|
||||
}
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
AssertLockHeld(spk_man->cs_wallet);
|
||||
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
|
||||
@ -718,12 +745,12 @@ UniValue importelectrumwallet(const JSONRPCRequest& request)
|
||||
CPubKey pubkey = key.GetPubKey();
|
||||
CHECK_NONFATAL(key.VerifyPubKey(pubkey));
|
||||
CKeyID keyid = pubkey.GetID();
|
||||
if (pwallet->HaveKey(keyid)) {
|
||||
if (spk_man->HaveKey(keyid)) {
|
||||
pwallet->WalletLogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid));
|
||||
continue;
|
||||
}
|
||||
pwallet->WalletLogPrintf("Importing %s...\n", EncodeDestination(keyid));
|
||||
if (!pwallet->AddKeyPubKeyWithDB(batch, key, pubkey)) {
|
||||
if (!spk_man->AddKeyPubKeyWithDB(batch, key, pubkey)) {
|
||||
fGood = false;
|
||||
continue;
|
||||
}
|
||||
@ -751,12 +778,12 @@ UniValue importelectrumwallet(const JSONRPCRequest& request)
|
||||
CPubKey pubkey = key.GetPubKey();
|
||||
CHECK_NONFATAL(key.VerifyPubKey(pubkey));
|
||||
CKeyID keyid = pubkey.GetID();
|
||||
if (pwallet->HaveKey(keyid)) {
|
||||
if (spk_man->HaveKey(keyid)) {
|
||||
pwallet->WalletLogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid));
|
||||
continue;
|
||||
}
|
||||
pwallet->WalletLogPrintf("Importing %s...\n", EncodeDestination(keyid));
|
||||
if (!pwallet->AddKeyPubKeyWithDB(batch, key, pubkey)) {
|
||||
if (!spk_man->AddKeyPubKeyWithDB(batch, key, pubkey)) {
|
||||
fGood = false;
|
||||
continue;
|
||||
}
|
||||
@ -776,7 +803,7 @@ UniValue importelectrumwallet(const JSONRPCRequest& request)
|
||||
|
||||
// Assume that electrum wallet was created at that block
|
||||
int nTimeBegin = pwallet->chain().getBlockTime(nStartHeight);
|
||||
pwallet->UpdateTimeFirstKey(nTimeBegin);
|
||||
spk_man->UpdateTimeFirstKey(nTimeBegin);
|
||||
|
||||
pwallet->WalletLogPrintf("Rescanning %i blocks\n", tip_height - nStartHeight + 1);
|
||||
WalletRescanReserver reserver(pwallet);
|
||||
@ -813,6 +840,11 @@ UniValue dumpprivkey(const JSONRPCRequest& request)
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
@ -827,7 +859,7 @@ UniValue dumpprivkey(const JSONRPCRequest& request)
|
||||
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);
|
||||
@ -860,11 +892,15 @@ UniValue dumphdinfo(const JSONRPCRequest& request)
|
||||
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
CHDChain hdChainCurrent;
|
||||
if (!pwallet->GetHDChain(hdChainCurrent))
|
||||
if (!spk_man->GetHDChain(hdChainCurrent))
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This wallet is not a HD wallet.");
|
||||
|
||||
if (!pwallet->GetDecryptedHDChain(hdChainCurrent))
|
||||
if (!spk_man->GetDecryptedHDChain(hdChainCurrent))
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Cannot decrypt HD seed");
|
||||
|
||||
SecureString ssMnemonic;
|
||||
@ -907,7 +943,13 @@ UniValue dumpwallet(const JSONRPCRequest& request)
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
AssertLockHeld(spk_man->cs_wallet);
|
||||
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
|
||||
@ -929,10 +971,10 @@ UniValue dumpwallet(const JSONRPCRequest& request)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
|
||||
|
||||
std::map<CTxDestination, int64_t> mapKeyBirth;
|
||||
const std::map<CKeyID, int64_t>& mapKeyPool = pwallet->GetAllReserveKeys();
|
||||
const std::map<CKeyID, int64_t>& mapKeyPool = spk_man->GetAllReserveKeys();
|
||||
pwallet->GetKeyBirthTimes(mapKeyBirth);
|
||||
|
||||
std::set<CScriptID> scripts = pwallet->GetCScripts();
|
||||
std::set<CScriptID> scripts = spk_man->GetCScripts();
|
||||
// TODO: include scripts in GetKeyBirthTimes() output instead of separate
|
||||
|
||||
// sort time/key pairs
|
||||
@ -961,10 +1003,10 @@ UniValue dumpwallet(const JSONRPCRequest& request)
|
||||
|
||||
// add the base58check encoded extended master if the wallet uses HD
|
||||
CHDChain hdChainCurrent;
|
||||
if (pwallet->GetHDChain(hdChainCurrent))
|
||||
if (spk_man->GetHDChain(hdChainCurrent))
|
||||
{
|
||||
|
||||
if (!pwallet->GetDecryptedHDChain(hdChainCurrent))
|
||||
if (!spk_man->GetDecryptedHDChain(hdChainCurrent))
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Cannot decrypt HD chain");
|
||||
|
||||
SecureString ssMnemonic;
|
||||
@ -1004,7 +1046,7 @@ UniValue dumpwallet(const JSONRPCRequest& request)
|
||||
std::string strTime = FormatISO8601DateTime(it->first);
|
||||
std::string strAddr = EncodeDestination(keyid);
|
||||
CKey key;
|
||||
if (pwallet->GetKey(keyid, key)) {
|
||||
if (spk_man->GetKey(keyid, key)) {
|
||||
file << strprintf("%s %s ", EncodeSecret(key), strTime);
|
||||
if (pwallet->mapAddressBook.count(keyid)) {
|
||||
file << strprintf("label=%s", EncodeDumpString(pwallet->mapAddressBook[keyid].name));
|
||||
@ -1013,7 +1055,7 @@ UniValue dumpwallet(const JSONRPCRequest& request)
|
||||
} 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";
|
||||
@ -1022,11 +1064,11 @@ UniValue dumpwallet(const JSONRPCRequest& request)
|
||||
std::string create_time = "0";
|
||||
std::string address = EncodeDestination(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), create_time);
|
||||
file << strprintf(" # addr=%s\n", address);
|
||||
}
|
||||
@ -1366,7 +1408,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) + "\")");
|
||||
}
|
||||
}
|
||||
@ -1497,6 +1539,11 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(mainRequest);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
|
||||
//Default options
|
||||
bool fRescan = true;
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <wallet/psbtwallet.h>
|
||||
#include <wallet/load.h>
|
||||
#include <wallet/rpcwallet.h>
|
||||
#include <wallet/scriptpubkeyman.h>
|
||||
#include <wallet/wallet.h>
|
||||
#include <wallet/walletdb.h>
|
||||
#include <wallet/walletutil.h>
|
||||
@ -63,7 +64,7 @@ static inline bool GetAvoidReuseFlag(CWallet * const pwallet, const UniValue& pa
|
||||
|
||||
/** 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());
|
||||
@ -188,6 +189,10 @@ UniValue getnewaddress(const JSONRPCRequest& request)
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
if (!pwallet->CanGetAddresses()) {
|
||||
@ -205,7 +210,7 @@ UniValue getnewaddress(const JSONRPCRequest& request)
|
||||
|
||||
// Generate a new key that is added to wallet
|
||||
CPubKey newKey;
|
||||
if (!pwallet->GetKeyFromPool(newKey, false)) {
|
||||
if (!spk_man->GetKeyFromPool(newKey, false)) {
|
||||
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
|
||||
}
|
||||
CKeyID keyID = newKey.GetID();
|
||||
@ -285,7 +290,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");
|
||||
@ -583,8 +588,10 @@ static UniValue signmessage(const JSONRPCRequest& request)
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
|
||||
}
|
||||
|
||||
const SigningProvider* provider = pwallet->GetSigningProvider();
|
||||
|
||||
CKey key;
|
||||
if (!pwallet->GetKey(*keyID, key)) {
|
||||
if (!provider->GetKey(*keyID, key)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
|
||||
}
|
||||
|
||||
@ -639,7 +646,7 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request)
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Dash address");
|
||||
}
|
||||
CScript scriptPubKey = GetScriptForDestination(dest);
|
||||
if (!IsMine(*pwallet, scriptPubKey)) {
|
||||
if (!pwallet->IsMine(scriptPubKey)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Address not found in wallet");
|
||||
}
|
||||
|
||||
@ -721,7 +728,7 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request)
|
||||
for (const CTxOut& txout : wtx.tx->vout)
|
||||
{
|
||||
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() >= nMinDepth) || (fAddLocked && wtx.IsLockedByInstantSend()))
|
||||
nAmount += txout.nValue;
|
||||
}
|
||||
@ -992,6 +999,11 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request)
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
std::string label;
|
||||
@ -1007,14 +1019,14 @@ 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()));
|
||||
}
|
||||
}
|
||||
|
||||
// Construct using pay-to-script-hash:
|
||||
CScript inner = CreateMultisigRedeemscript(required, pubkeys);
|
||||
CScriptID innerID(inner);
|
||||
pwallet->AddCScript(inner);
|
||||
spk_man->AddCScript(inner);
|
||||
|
||||
pwallet->SetAddressBook(innerID, label, "send");
|
||||
|
||||
@ -1088,7 +1100,7 @@ static UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bo
|
||||
continue;
|
||||
}
|
||||
|
||||
isminefilter mine = IsMine(*pwallet, address);
|
||||
isminefilter mine = pwallet->IsMine(address);
|
||||
if(!(mine & filter))
|
||||
continue;
|
||||
|
||||
@ -1125,7 +1137,7 @@ static UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bo
|
||||
if (it == mapTally.end() && !fIncludeEmpty)
|
||||
continue;
|
||||
|
||||
isminefilter mine = IsMine(*pwallet, address);
|
||||
isminefilter mine = pwallet->IsMine(address);
|
||||
if(!(mine & filter))
|
||||
continue;
|
||||
|
||||
@ -1314,7 +1326,7 @@ static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, int n
|
||||
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);
|
||||
@ -1346,7 +1358,7 @@ static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, int n
|
||||
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);
|
||||
@ -2425,8 +2437,9 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
CHDChain hdChainCurrent;
|
||||
bool fHDEnabled = pwallet->GetHDChain(hdChainCurrent);
|
||||
bool fHDEnabled = spk_man && spk_man->GetHDChain(hdChainCurrent);
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
|
||||
const auto bal = pwallet->GetBalance();
|
||||
@ -2437,10 +2450,13 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
|
||||
obj.pushKV("unconfirmed_balance", ValueFromAmount(bal.m_mine_untrusted_pending));
|
||||
obj.pushKV("immature_balance", ValueFromAmount(bal.m_mine_immature));
|
||||
obj.pushKV("txcount", (int)pwallet->mapWallet.size());
|
||||
obj.pushKV("timefirstkey", pwallet->GetTimeFirstKey());
|
||||
obj.pushKV("keypoololdest", pwallet->GetOldestKeyPoolTime());
|
||||
obj.pushKV("keypoolsize", (int64_t)pwallet->KeypoolCountExternalKeys());
|
||||
obj.pushKV("keypoolsize_hd_internal", (int64_t)(pwallet->KeypoolCountInternalKeys()));
|
||||
if (spk_man) {
|
||||
AssertLockHeld(spk_man->cs_wallet);
|
||||
obj.pushKV("timefirstkey", spk_man->GetTimeFirstKey());
|
||||
obj.pushKV("keypoololdest", spk_man->GetOldestKeyPoolTime());
|
||||
obj.pushKV("keypoolsize", (int64_t)spk_man->KeypoolCountExternalKeys());
|
||||
obj.pushKV("keypoolsize_hd_internal", (int64_t)(spk_man->KeypoolCountInternalKeys()));
|
||||
}
|
||||
obj.pushKV("keys_left", pwallet->nKeysLeftSinceAutoBackup);
|
||||
if (pwallet->IsCrypted())
|
||||
obj.pushKV("unlocked_until", pwallet->nRelockTime);
|
||||
@ -2565,6 +2581,10 @@ static UniValue upgradetohd(const JSONRPCRequest& request)
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (!spk_man) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
|
||||
}
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
@ -2619,11 +2639,11 @@ static UniValue upgradetohd(const JSONRPCRequest& request)
|
||||
pwallet->SetMinVersion(FEATURE_HD);
|
||||
|
||||
if (prev_encrypted) {
|
||||
if (!pwallet->GenerateNewHDChainEncrypted(secureMnemonic, secureMnemonicPassphrase, secureWalletPassphrase)) {
|
||||
if (!spk_man->GenerateNewHDChainEncrypted(secureMnemonic, secureMnemonicPassphrase, secureWalletPassphrase)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Failed to generate encrypted HD wallet");
|
||||
}
|
||||
} else {
|
||||
pwallet->GenerateNewHDChain(secureMnemonic, secureMnemonicPassphrase);
|
||||
spk_man->GenerateNewHDChain(secureMnemonic, secureMnemonicPassphrase);
|
||||
if (!secureWalletPassphrase.empty()) {
|
||||
if (!pwallet->EncryptWallet(secureWalletPassphrase)) {
|
||||
throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Failed to encrypt HD wallet");
|
||||
@ -3061,10 +3081,11 @@ static UniValue listunspent(const JSONRPCRequest& request)
|
||||
entry.pushKV("label", i->second.name);
|
||||
}
|
||||
|
||||
const SigningProvider* provider = pwallet->GetSigningProvider();
|
||||
if (scriptPubKey.IsPayToScriptHash()) {
|
||||
const CScriptID& hash = boost::get<CScriptID>(address);
|
||||
CScript redeemScript;
|
||||
if (pwallet->GetCScript(hash, redeemScript)) {
|
||||
if (provider->GetCScript(hash, redeemScript)) {
|
||||
entry.pushKV("redeemScript", HexStr(redeemScript));
|
||||
}
|
||||
}
|
||||
@ -3076,7 +3097,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);
|
||||
@ -3349,7 +3370,7 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request)
|
||||
}
|
||||
pwallet->chain().findCoins(coins);
|
||||
|
||||
return SignTransaction(mtx, request.params[1], pwallet, coins, false, request.params[2]);
|
||||
return SignTransaction(mtx, request.params[1], &*pwallet->GetLegacyScriptPubKeyMan(), coins, false, request.params[2]);
|
||||
}
|
||||
|
||||
static UniValue rescanblockchain(const JSONRPCRequest& request)
|
||||
@ -3443,16 +3464,16 @@ static UniValue rescanblockchain(const JSONRPCRequest& request)
|
||||
class DescribeWalletAddressVisitor : public boost::static_visitor<UniValue>
|
||||
{
|
||||
public:
|
||||
CWallet * const pwallet;
|
||||
const SigningProvider * const provider;
|
||||
|
||||
explicit DescribeWalletAddressVisitor(CWallet *_pwallet) : pwallet(_pwallet) {}
|
||||
explicit DescribeWalletAddressVisitor(const SigningProvider * const _provider) : provider(_provider) {}
|
||||
|
||||
UniValue operator()(const CNoDestination &dest) const { return UniValue(UniValue::VOBJ); }
|
||||
|
||||
UniValue operator()(const CKeyID &keyID) const {
|
||||
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());
|
||||
}
|
||||
@ -3462,7 +3483,7 @@ public:
|
||||
UniValue operator()(const CScriptID &scriptID) const {
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
CScript subscript;
|
||||
if (pwallet && pwallet->GetCScript(scriptID, subscript)) {
|
||||
if (provider && provider->GetCScript(scriptID, subscript)) {
|
||||
std::vector<CTxDestination> addresses;
|
||||
txnouttype whichType;
|
||||
int nRequired;
|
||||
@ -3485,8 +3506,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;
|
||||
}
|
||||
|
||||
@ -3571,13 +3596,14 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
|
||||
|
||||
CScript scriptPubKey = GetScriptForDestination(dest);
|
||||
ret.pushKV("scriptPubKey", HexStr(scriptPubKey));
|
||||
const SigningProvider* provider = pwallet->GetSigningProvider();
|
||||
|
||||
isminetype mine = IsMine(*pwallet, dest);
|
||||
isminetype mine = pwallet->IsMine(dest);
|
||||
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);
|
||||
@ -3603,9 +3629,14 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
|
||||
if (meta) {
|
||||
ret.pushKV("timestamp", meta->nCreateTime);
|
||||
CHDChain hdChainCurrent;
|
||||
if (key_id && pwallet->mapHdPubKeys.count(*key_id) && pwallet->GetHDChain(hdChainCurrent)) {
|
||||
LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (spk_man != nullptr) {
|
||||
LOCK(pwallet->cs_KeyStore);
|
||||
AssertLockHeld(spk_man->cs_KeyStore);
|
||||
if (key_id && pwallet->mapHdPubKeys.count(*key_id) && spk_man->GetHDChain(hdChainCurrent)) {
|
||||
ret.pushKV("hdchainid", hdChainCurrent.GetID().GetHex());
|
||||
}
|
||||
}
|
||||
if (meta->has_key_origin) {
|
||||
ret.pushKV("hdkeypath", WriteHDKeypath(meta->key_origin.path));
|
||||
ret.pushKV("hdmasterfingerprint", HexStr(meta->key_origin.fingerprint));
|
||||
|
1598
src/wallet/scriptpubkeyman.cpp
Normal file
1598
src/wallet/scriptpubkeyman.cpp
Normal file
File diff suppressed because it is too large
Load Diff
372
src/wallet/scriptpubkeyman.h
Normal file
372
src/wallet/scriptpubkeyman.h
Normal file
@ -0,0 +1,372 @@
|
||||
// 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 bool CanSupportFeature(enum WalletFeature) const = 0;
|
||||
virtual void SetMinVersion(enum WalletFeature, WalletBatch* = nullptr, bool = false) = 0;
|
||||
virtual bool IsLocked(bool fForMixing = false) const = 0;
|
||||
};
|
||||
|
||||
//! Default for -keypool
|
||||
static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
|
||||
|
||||
/** A key from a CWallet's keypool
|
||||
*
|
||||
* The wallet holds 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.
|
||||
*
|
||||
* 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 and
|
||||
* setExternalKeyPool), 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;
|
||||
|
||||
CKeyPool();
|
||||
CKeyPool(const CPubKey& vchPubKeyIn, bool fInternalIn);
|
||||
|
||||
template<typename Stream>
|
||||
void Serialize(Stream& s) const
|
||||
{
|
||||
int nVersion = s.GetVersion();
|
||||
if (!(s.GetType() & SER_GETHASH)) {
|
||||
s << nVersion;
|
||||
}
|
||||
s << nTime << vchPubKey << fInternal;
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream& s)
|
||||
{
|
||||
int nVersion = s.GetVersion();
|
||||
if (!(s.GetType() & SER_GETHASH)) {
|
||||
s >> nVersion;
|
||||
}
|
||||
s >> nTime >> vchPubKey;
|
||||
try {
|
||||
s >> 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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* 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>;
|
||||
using HDPubKeyMap = std::map<CKeyID, CHDPubKey>;
|
||||
|
||||
//! 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);
|
||||
HDPubKeyMap mapHdPubKeys GUARDED_BY(cs_KeyStore); //<! memory map of HD extended pubkeys
|
||||
|
||||
bool HaveKeyInner(const CKeyID &address) const;
|
||||
bool AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
|
||||
bool AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey);
|
||||
bool GetKeyInner(const CKeyID &address, CKey& keyOut) const;
|
||||
bool GetPubKeyInner(const CKeyID &address, CPubKey& vchPubKeyOut) const;
|
||||
|
||||
WalletBatch *encrypted_batch GUARDED_BY(cs_wallet) = nullptr;
|
||||
|
||||
/* the HD chain data model (external chain counters) */
|
||||
CHDChain hdChain GUARDED_BY(cs_KeyStore);
|
||||
CHDChain cryptedHDChain GUARDED_BY(cs_KeyStore);
|
||||
|
||||
/* HD derive new child key (on internal or external chain) */
|
||||
void DeriveNewChildKey(WalletBatch& batch, CKeyMetadata& metadata, CKey& secretRet, uint32_t nAccountIndex, bool fInternal /*= false*/) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
||||
std::set<int64_t> setInternalKeyPool GUARDED_BY(cs_wallet);
|
||||
std::set<int64_t> setExternalKeyPool 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 AddWatchOnlyInMem(const CScript &dest);
|
||||
|
||||
/** Add a KeyOriginInfo to the wallet */
|
||||
bool AddKeyOriginWithDB(WalletBatch& batch, const CPubKey& pubkey, const KeyOriginInfo& info);
|
||||
|
||||
void AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const bool internal, WalletBatch& batch);
|
||||
|
||||
public:
|
||||
//! 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);
|
||||
|
||||
//! Adds a script to the store and saves it to disk
|
||||
bool AddCScriptWithDB(WalletBatch& batch, const CScript& script);
|
||||
|
||||
public:
|
||||
void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool) 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);
|
||||
|
||||
bool WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, bool overwrite);
|
||||
|
||||
/**
|
||||
* keystore implementation
|
||||
* Generate a new key
|
||||
*/
|
||||
CPubKey GenerateNewKey(WalletBatch& batch, uint32_t nAccountIndex, bool fInternal /*= 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);
|
||||
int64_t GetTimeFirstKey() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
||||
//! Adds an encrypted key to the store, and saves it to disk.
|
||||
bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
|
||||
//! 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);
|
||||
//! GetKey implementation that can derive a HD private key on the fly
|
||||
bool GetKey(const CKeyID &address, CKey& keyOut) const override;
|
||||
//! GetPubKey implementation that also checks the mapHdPubKeys
|
||||
bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
|
||||
//! HaveKey implementation that also checks the mapHdPubKeys
|
||||
bool HaveKey(const CKeyID &address) const override;
|
||||
//! Adds a HDPubKey into the wallet(database)
|
||||
bool AddHDPubKey(WalletBatch &batch, const CExtPubKey &extPubKey, bool fInternal);
|
||||
//! loads a HDPubKey into the wallets memory
|
||||
bool LoadHDPubKey(const CHDPubKey &hdPubKey) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
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 AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest) 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) 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);
|
||||
size_t KeypoolCountInternalKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
bool TopUpKeyPool(unsigned int kpSize = 0);
|
||||
void AddKeypoolPubkey(const CPubKey& pubkey, const bool internal);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
bool GetKeyFromPool(CPubKey &key, bool fInternal /*= false*/);
|
||||
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; }
|
||||
|
||||
isminetype IsMine(const CScript& script) const;
|
||||
isminetype IsMine(const CTxDestination& dest) const;
|
||||
|
||||
/**
|
||||
* HD Wallet Functions
|
||||
*/
|
||||
|
||||
bool EncryptHDChain(const CKeyingMaterial& vMasterKeyIn, const CHDChain& chain = CHDChain());
|
||||
bool DecryptHDChain(CHDChain& hdChainRet) const;
|
||||
bool SetHDChain(const CHDChain& chain);
|
||||
bool GetHDChain(CHDChain& hdChainRet) const;
|
||||
bool SetCryptedHDChain(const CHDChain& chain);
|
||||
bool GetDecryptedHDChain(CHDChain& hdChainRet);
|
||||
|
||||
/* 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 chain */
|
||||
void GenerateNewHDChain(const SecureString& secureMnemonic, const SecureString& secureMnemonicPassphrase);
|
||||
bool GenerateNewHDChainEncrypted(const SecureString& secureMnemonic, const SecureString& secureMnemonicPassphrase, const SecureString& secureWalletPassphrase);
|
||||
|
||||
/* Set the HD chain model (chain child index counters) */
|
||||
bool SetHDChain(WalletBatch &batch, const CHDChain& chain, bool memonly);
|
||||
bool SetCryptedHDChain(WalletBatch &batch, const CHDChain& chain, bool memonly);
|
||||
/**
|
||||
* Set the HD chain model (chain child index counters) using temporary wallet db object
|
||||
* which causes db flush every time these methods are used
|
||||
*/
|
||||
bool SetHDChainSingle(const CHDChain& chain, bool memonly);
|
||||
bool SetCryptedHDChainSingle(const CHDChain& chain, bool memonly);
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/** Add a KeyOriginInfo to the wallet */
|
||||
bool AddKeyOrigin(const CPubKey& pubkey, const KeyOriginInfo& info);
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_WALLET_SCRIPTPUBKEYMAN_H
|
@ -137,7 +137,7 @@ public:
|
||||
AddWallet(wallet);
|
||||
{
|
||||
LOCK2(wallet->cs_wallet, cs_main);
|
||||
wallet->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
|
||||
wallet->GetLegacyScriptPubKeyMan()->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
|
||||
wallet->SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
|
||||
WalletRescanReserver reserver(wallet.get());
|
||||
reserver.reserve();
|
||||
|
@ -40,12 +40,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);
|
||||
}
|
||||
|
||||
@ -56,12 +56,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);
|
||||
}
|
||||
|
||||
@ -72,12 +72,12 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
||||
scriptPubKey = GetScriptForDestination(pubkeys[0].GetID());
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
@ -88,12 +88,12 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
||||
scriptPubKey = GetScriptForDestination(uncompressedPubkey.GetID());
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
@ -106,17 +106,17 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
||||
scriptPubKey = GetScriptForDestination(CScriptID(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);
|
||||
}
|
||||
|
||||
@ -129,11 +129,11 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
||||
CScript redeemscript = GetScriptForDestination(CScriptID(redeemscript_inner));
|
||||
scriptPubKey = GetScriptForDestination(CScriptID(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);
|
||||
}
|
||||
|
||||
@ -145,25 +145,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);
|
||||
}
|
||||
|
||||
@ -171,19 +171,19 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
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(CScriptID(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);
|
||||
}
|
||||
|
||||
@ -191,12 +191,12 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
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);
|
||||
}
|
||||
|
||||
@ -204,12 +204,12 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,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
|
||||
@ -34,17 +35,17 @@ 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);
|
||||
|
||||
// Call FillPSBT
|
||||
PartiallySignedTransaction psbtx;
|
||||
|
@ -33,8 +33,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)
|
||||
@ -223,9 +225,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(), CreateDummyWalletDatabase());
|
||||
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());
|
||||
|
||||
util::Ref context;
|
||||
JSONRPCRequest request(context);
|
||||
@ -274,9 +278,11 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
|
||||
auto chain = interfaces::MakeChain(node);
|
||||
|
||||
CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
auto spk_man = wallet.GetLegacyScriptPubKeyMan();
|
||||
CWalletTx wtx(&wallet, m_coinbase_txns.back());
|
||||
|
||||
LOCK(wallet.cs_wallet);
|
||||
AssertLockHeld(spk_man->cs_wallet);
|
||||
wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
|
||||
|
||||
CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, ::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash(), 0);
|
||||
@ -286,10 +292,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(), 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(), 500*COIN);
|
||||
}
|
||||
|
||||
@ -1003,7 +1009,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
|
||||
wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
|
||||
BOOST_CHECK(!wallet->TopUpKeyPool(1000));
|
||||
CPubKey pubkey;
|
||||
BOOST_CHECK(!wallet->GetKeyFromPool(pubkey, false));
|
||||
BOOST_CHECK(!wallet->GetLegacyScriptPubKeyMan()->GetKeyFromPool(pubkey, false));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -20,7 +20,7 @@
|
||||
#include <wallet/coincontrol.h>
|
||||
#include <wallet/crypter.h>
|
||||
#include <wallet/coinselection.h>
|
||||
#include <wallet/ismine.h>
|
||||
#include <wallet/scriptpubkeyman.h>
|
||||
#include <wallet/walletdb.h>
|
||||
#include <wallet/walletutil.h>
|
||||
|
||||
@ -67,7 +67,6 @@ enum class WalletCreationStatus {
|
||||
|
||||
WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, Optional<bool> load_on_start, bilingual_str& error, std::vector<bilingual_str>& warnings, std::shared_ptr<CWallet>& result);
|
||||
|
||||
static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
|
||||
//! -paytxfee default
|
||||
constexpr CAmount DEFAULT_PAY_TX_FEE = 0;
|
||||
//! -fallbackfee default
|
||||
@ -111,18 +110,6 @@ enum class FeeEstimateMode;
|
||||
extern CCriticalSection cs_main;
|
||||
|
||||
/** (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 = 120200, // Hierarchical key derivation after BIP32 (HD Wallet), BIP44 (multi-coin), BIP39 (mnemonic)
|
||||
// which uses on-the-fly private key derivation
|
||||
|
||||
FEATURE_LATEST = FEATURE_HD
|
||||
};
|
||||
|
||||
struct CompactTallyItem
|
||||
{
|
||||
CTxDestination txdest;
|
||||
@ -131,33 +118,6 @@ struct CompactTallyItem
|
||||
CompactTallyItem() = default;
|
||||
};
|
||||
|
||||
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
|
||||
@ -176,89 +136,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 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.
|
||||
*
|
||||
* 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 and
|
||||
* setExternalKeyPool), 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;
|
||||
|
||||
CKeyPool();
|
||||
CKeyPool(const CPubKey& vchPubKeyIn, bool fInternalIn);
|
||||
|
||||
template<typename Stream>
|
||||
void Serialize(Stream& s) const
|
||||
{
|
||||
int nVersion = s.GetVersion();
|
||||
if (!(s.GetType() & SER_GETHASH)) {
|
||||
s << nVersion;
|
||||
}
|
||||
s << nTime << vchPubKey << fInternal;
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream& s)
|
||||
{
|
||||
int nVersion = s.GetVersion();
|
||||
if (!(s.GetType() & SER_GETHASH)) {
|
||||
s >> nVersion;
|
||||
}
|
||||
s >> nTime >> vchPubKey;
|
||||
try {
|
||||
s >> 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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** A wrapper to reserve a key from a wallet keypool
|
||||
*
|
||||
* CReserveKey is used to reserve a key from the keypool. It is passed around
|
||||
@ -279,6 +156,7 @@ class CReserveKey final : public CReserveScript
|
||||
protected:
|
||||
//! The wallet to reserve the keypool key from
|
||||
CWallet* pwallet;
|
||||
LegacyScriptPubKeyMan* m_spk_man{nullptr};
|
||||
//! The index of the key in the keypool
|
||||
int64_t nIndex{-1};
|
||||
//! The public key
|
||||
@ -763,14 +641,11 @@ struct CoinSelectionParams
|
||||
|
||||
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, public interfaces::Chain::Notifications
|
||||
class CWallet final : public WalletStorage, public interfaces::Chain::Notifications
|
||||
{
|
||||
private:
|
||||
CHDChain cryptedHDChain GUARDED_BY(cs_KeyStore);
|
||||
|
||||
CKeyingMaterial vMasterKey GUARDED_BY(cs_KeyStore);
|
||||
|
||||
//! if fUseCrypto is true, mapKeys must be empty
|
||||
@ -783,30 +658,9 @@ private:
|
||||
//! if fOnlyMixingAllowed is true, only mixing should be allowed in unlocked wallet
|
||||
bool fOnlyMixingAllowed;
|
||||
|
||||
using CryptedKeyMap = std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char>>>;
|
||||
using WatchOnlySet = std::set<CScript>;
|
||||
using WatchKeyMap = std::map<CKeyID, CPubKey>;
|
||||
|
||||
bool SetCrypted();
|
||||
|
||||
//! will encrypt previously unencrypted keys
|
||||
bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
|
||||
|
||||
bool EncryptHDChain(const CKeyingMaterial& vMasterKeyIn, const CHDChain& chain = CHDChain());
|
||||
bool DecryptHDChain(CHDChain& hdChainRet) const;
|
||||
bool SetHDChain(const CHDChain& chain);
|
||||
bool SetCryptedHDChain(const CHDChain& chain);
|
||||
|
||||
bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool fForMixingOnly = false, bool accept_no_keys = false);
|
||||
CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore);
|
||||
WatchOnlySet setWatchOnly GUARDED_BY(cs_KeyStore);
|
||||
WatchKeyMap mapWatchKeys GUARDED_BY(cs_KeyStore);
|
||||
|
||||
bool HaveKeyInner(const CKeyID &address) const;
|
||||
bool AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
|
||||
bool AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey);
|
||||
bool GetKeyInner(const CKeyID &address, CKey& keyOut) const;
|
||||
bool GetPubKeyInner(const CKeyID &address, CPubKey& vchPubKeyOut) const;
|
||||
|
||||
std::atomic<bool> fAbortRescan{false};
|
||||
std::atomic<bool> fScanningWallet{false}; // controlled by WalletRescanReserver
|
||||
@ -814,8 +668,6 @@ private:
|
||||
std::atomic<double> m_scanning_progress{0};
|
||||
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};
|
||||
|
||||
@ -873,29 +725,8 @@ 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::Confirmation confirm, bool update_tx = true) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
||||
/* HD derive new child key (on internal or external chain) */
|
||||
void DeriveNewChildKey(WalletBatch& batch, CKeyMetadata& metadata, CKey& secretRet, uint32_t nAccountIndex, bool fInternal /*= false*/) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
||||
std::set<int64_t> setInternalKeyPool GUARDED_BY(cs_wallet);
|
||||
std::set<int64_t> setExternalKeyPool 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 AddWatchOnlyInMem(const CScript &dest);
|
||||
|
||||
/** Interface for accessing chain state. */
|
||||
interfaces::Chain* m_chain;
|
||||
|
||||
@ -949,6 +780,7 @@ public:
|
||||
{
|
||||
return *database;
|
||||
}
|
||||
WalletDatabase& GetDatabase() override { return *database; }
|
||||
|
||||
/**
|
||||
* Select a set of coins such that nValueRet >= nTargetValue and at least
|
||||
@ -964,19 +796,9 @@ public:
|
||||
*/
|
||||
const std::string& GetName() const { return m_location.GetName(); }
|
||||
|
||||
void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool) 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);
|
||||
|
||||
// Map from governance object hash to governance object, they are added by gobject_prepare.
|
||||
std::map<uint256, CGovernanceObject> m_gobjects;
|
||||
|
||||
bool WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, bool overwrite);
|
||||
|
||||
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
|
||||
MasterKeyMap mapMasterKeys;
|
||||
unsigned int nMasterKeyMaxID = 0;
|
||||
@ -1003,7 +825,7 @@ public:
|
||||
/** Interface to assert chain access */
|
||||
bool HaveChain() const { return m_chain ? true : false; }
|
||||
bool IsCrypted() const { return fUseCrypto; }
|
||||
bool IsLocked(bool fForMixing = false) const;
|
||||
bool IsLocked(bool fForMixing = false) const override;
|
||||
bool Lock(bool fForMixing = false);
|
||||
|
||||
std::map<uint256, CWalletTx> mapWallet GUARDED_BY(cs_wallet);
|
||||
@ -1020,8 +842,6 @@ public:
|
||||
|
||||
int64_t nKeysLeftSinceAutoBackup;
|
||||
|
||||
std::map<CKeyID, CHDPubKey> mapHdPubKeys; //<! memory map of HD extended pubkeys
|
||||
|
||||
/** Registered interfaces::Chain::Notifications handler. */
|
||||
std::unique_ptr<interfaces::Handler> m_chain_notifications_handler;
|
||||
|
||||
@ -1031,7 +851,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.
|
||||
@ -1098,43 +918,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, uint32_t nAccountIndex, bool fInternal /*= false*/) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
//! HaveKey implementation that also checks the mapHdPubKeys
|
||||
bool HaveKey(const CKeyID &address) const override;
|
||||
//! GetPubKey implementation that also checks the mapHdPubKeys
|
||||
bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
|
||||
//! GetKey implementation that can derive a HD private key on the fly
|
||||
bool GetKey(const CKeyID &address, CKey& keyOut) const override;
|
||||
//! Adds a HDPubKey into the wallet(database)
|
||||
bool AddHDPubKey(WalletBatch &batch, const CExtPubKey &extPubKey, bool fInternal);
|
||||
//! loads a HDPubKey into the wallets memory
|
||||
bool LoadHDPubKey(const CHDPubKey &hdPubKey) 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);
|
||||
int64_t GetTimeFirstKey() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
||||
//! Adds an encrypted key to the store, and saves it to disk.
|
||||
bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
|
||||
//! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
|
||||
bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
|
||||
std::set<CKeyID> GetKeys() const override;
|
||||
virtual bool GetHDChain(CHDChain& hdChainRet) const override;
|
||||
bool AddCScript(const CScript& redeemScript) override;
|
||||
bool LoadCScript(const CScript& redeemScript);
|
||||
|
||||
//! 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);
|
||||
@ -1147,30 +934,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 AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
bool RemoveWatchOnly(const CScript &dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
//! Adds a watch-only address to the store, without saving it to disk (used by LoadWallet)
|
||||
bool LoadWatchOnly(const CScript &dest);
|
||||
//! Returns whether the watch-only script is in the wallet
|
||||
bool HaveWatchOnly(const CScript &dest) const;
|
||||
//! Returns whether there are any watch-only things in the wallet
|
||||
bool HaveWatchOnly() const;
|
||||
//! Fetches a pubkey from mapWatchKeys if it exists there
|
||||
bool GetWatchPubKey(const CKeyID &address, CPubKey &pubkey_out) const;
|
||||
|
||||
//! Adds a key to the store, and saves it to disk.
|
||||
bool AddKeyPubKeyWithDB(WalletBatch &batch,const CKey& key, const CPubKey &pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
||||
//! 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);
|
||||
|
||||
//! Adds a script to the store and saves it to disk
|
||||
bool AddCScriptWithDB(WalletBatch& batch, const CScript& script);
|
||||
|
||||
bool SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::string& strPurpose);
|
||||
|
||||
//! 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;
|
||||
|
||||
@ -1289,43 +1052,21 @@ 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);
|
||||
size_t KeypoolCountInternalKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
bool TopUpKeyPool(unsigned int kpSize = 0);
|
||||
void AddKeypoolPubkey(const CPubKey& pubkey, const bool internal);
|
||||
void AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const bool internal, WalletBatch& batch);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
bool GetKeyFromPool(CPubKey &key, bool fInternal /*= false*/);
|
||||
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();
|
||||
|
||||
std::set<CTxDestination> GetLabelAddresses(const std::string& label) const;
|
||||
|
||||
bool GetNewChangeDestination(const OutputType type, CTxDestination& dest, std::string& error);
|
||||
|
||||
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
|
||||
@ -1351,6 +1092,7 @@ public:
|
||||
void AutoLockMasternodeCollaterals();
|
||||
DBErrors ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
||||
bool SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::string& strPurpose);
|
||||
bool SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& purpose);
|
||||
|
||||
bool DelAddressBook(const CTxDestination& address);
|
||||
@ -1362,7 +1104,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);
|
||||
@ -1461,27 +1203,9 @@ public:
|
||||
/* 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 chain */
|
||||
void GenerateNewHDChain(const SecureString& secureMnemonic, const SecureString& secureMnemonicPassphrase);
|
||||
bool GenerateNewHDChainEncrypted(const SecureString& secureMnemonic, const SecureString& secureMnemonicPassphrase, const SecureString& secureWalletPassphrase);
|
||||
/* Set the HD chain model (chain child index counters) */
|
||||
bool SetHDChain(WalletBatch &batch, const CHDChain& chain, bool memonly);
|
||||
bool SetCryptedHDChain(WalletBatch &batch, const CHDChain& chain, bool memonly);
|
||||
/**
|
||||
* Set the HD chain model (chain child index counters) using temporary wallet db object
|
||||
* which causes db flush every time these methods are used
|
||||
*/
|
||||
bool SetHDChainSingle(const CHDChain& chain, bool memonly);
|
||||
bool SetCryptedHDChainSingle(const CHDChain& chain, bool memonly);
|
||||
|
||||
bool GetDecryptedHDChain(CHDChain& hdChainRet);
|
||||
|
||||
void NotifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr<const llmq::CInstantSendLock>& islock) override;
|
||||
void NotifyChainLock(const CBlockIndex* pindexChainLock, const std::shared_ptr<const llmq::CChainLockSig>& clsig) override;
|
||||
|
||||
@ -1500,23 +1224,22 @@ public:
|
||||
*/
|
||||
void BlockUntilSyncedToCurrentChain() LOCKS_EXCLUDED(cs_main, cs_wallet);
|
||||
|
||||
|
||||
/** 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);
|
||||
void UnsetWalletFlag(WalletBatch& batch, 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);
|
||||
};
|
||||
@ -1527,12 +1250,6 @@ 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;
|
||||
|
||||
/** Add a KeyOriginInfo to the wallet */
|
||||
bool AddKeyOrigin(const CPubKey& pubkey, const KeyOriginInfo& info);
|
||||
|
||||
/** Get last block processed height */
|
||||
int GetLastBlockHeight() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
|
||||
{
|
||||
@ -1547,6 +1264,29 @@ public:
|
||||
m_last_block_processed_height = block_height;
|
||||
m_last_block_processed = block_hash;
|
||||
};
|
||||
|
||||
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;
|
||||
LegacyScriptPubKeyMan::HDPubKeyMap& mapHdPubKeys GUARDED_BY(cs_KeyStore) = m_spk_man->mapHdPubKeys;
|
||||
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 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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -222,7 +222,7 @@ public:
|
||||
|
||||
static bool
|
||||
ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||
CWalletScanState &wss, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn = nullptr) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
|
||||
CWalletScanState &wss, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn = nullptr) 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
|
||||
@ -397,15 +399,15 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||
ssKey >> nIndex;
|
||||
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) {
|
||||
@ -419,7 +421,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||
} else if (strType == DBKeys::HDCHAIN) {
|
||||
CHDChain chain;
|
||||
ssValue >> chain;
|
||||
if (!pwallet->SetHDChainSingle(chain, true))
|
||||
if (!pwallet->GetLegacyScriptPubKeyMan()->SetHDChainSingle(chain, true))
|
||||
{
|
||||
strErr = "Error reading wallet database: SetHDChain failed";
|
||||
return false;
|
||||
@ -427,7 +429,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||
} else if (strType == DBKeys::CRYPTED_HDCHAIN) {
|
||||
CHDChain chain;
|
||||
ssValue >> chain;
|
||||
if (!pwallet->SetCryptedHDChainSingle(chain, true))
|
||||
if (!pwallet->GetLegacyScriptPubKeyMan()->SetCryptedHDChainSingle(chain, true))
|
||||
{
|
||||
strErr = "Error reading wallet database: SetHDCryptedChain failed";
|
||||
return false;
|
||||
@ -445,7 +447,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||
strErr = "Error reading wallet database: CHDPubKey corrupt";
|
||||
return false;
|
||||
}
|
||||
if (!pwallet->LoadHDPubKey(hdPubKey))
|
||||
if (!pwallet->GetLegacyScriptPubKeyMan()->LoadHDPubKey(hdPubKey))
|
||||
{
|
||||
strErr = "Error reading wallet database: LoadHDPubKey failed";
|
||||
return false;
|
||||
@ -497,6 +499,7 @@ bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, st
|
||||
{
|
||||
CWalletScanState dummy_wss;
|
||||
LOCK(pwallet->cs_wallet);
|
||||
AssertLockHeld(pwallet->GetLegacyScriptPubKeyMan()->cs_wallet);
|
||||
return ReadKeyValue(pwallet, ssKey, ssValue, dummy_wss, strType, strErr, filter_fn);
|
||||
}
|
||||
|
||||
@ -514,6 +517,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 +601,13 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
|
||||
wss.nWatchKeys, wss.nHDPubKeys, wss.nKeyMeta, wss.m_unknown_records);
|
||||
|
||||
// nTimeFirstKey is only reliable if all keys have metadata
|
||||
if ((wss.nKeys + wss.nCKeys + wss.nWatchKeys + wss.nHDPubKeys) != wss.nKeyMeta)
|
||||
pwallet->UpdateTimeFirstKey(1);
|
||||
if ((wss.nKeys + wss.nCKeys + wss.nWatchKeys + wss.nHDPubKeys) != wss.nKeyMeta) {
|
||||
auto spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (spk_man) {
|
||||
AssertLockHeld(spk_man->cs_wallet);
|
||||
spk_man->UpdateTimeFirstKey(1);
|
||||
}
|
||||
}
|
||||
|
||||
for (const uint256& hash : wss.vWalletUpgrade)
|
||||
WriteTx(pwallet->mapWallet.at(hash));
|
||||
@ -616,7 +625,11 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
|
||||
// Upgrade all of the wallet keymetadata to have the hd master key id
|
||||
// This operation is not atomic, but if it fails, updated entries are still backwards compatible with older software
|
||||
try {
|
||||
pwallet->UpgradeKeyMetadata();
|
||||
auto spk_man = pwallet->GetLegacyScriptPubKeyMan();
|
||||
if (spk_man) {
|
||||
AssertLockHeld(spk_man->cs_wallet);
|
||||
spk_man->UpgradeKeyMetadata();
|
||||
}
|
||||
} catch (...) {
|
||||
result = DBErrors::CORRUPT;
|
||||
}
|
||||
|
@ -40,7 +40,8 @@ static std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::
|
||||
|
||||
// generate a new HD seed
|
||||
// NOTE: we do not yet create HD wallets by default
|
||||
// wallet_instance->GenerateNewHDChain("", "");
|
||||
// auto spk_man = wallet_instance->GetLegacyScriptPubKeyMan();
|
||||
// spk_man->GenerateNewHDChain("", "");
|
||||
|
||||
tfm::format(std::cout, "Topping up keypool...\n");
|
||||
wallet_instance->TopUpKeyPool();
|
||||
@ -98,7 +99,7 @@ static void WalletShowInfo(CWallet* wallet_instance)
|
||||
CHDChain hdChainTmp;
|
||||
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(hdChainTmp) ? "yes" : "no");
|
||||
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,47 @@
|
||||
|
||||
#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 = 120200, // Hierarchical key derivation after BIP32 (HD Wallet), BIP44 (multi-coin), BIP39 (mnemonic)
|
||||
// which uses on-the-fly private key derivation
|
||||
|
||||
FEATURE_LATEST = FEATURE_HD
|
||||
};
|
||||
|
||||
|
||||
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();
|
||||
|
||||
|
@ -27,7 +27,7 @@ EXPECTED_CIRCULAR_DEPENDENCIES=(
|
||||
"wallet/wallet -> wallet/walletdb -> wallet/wallet"
|
||||
"wallet/coincontrol -> wallet/wallet -> wallet/coincontrol"
|
||||
"txmempool -> validation -> validationinterface -> txmempool"
|
||||
"wallet/ismine -> wallet/wallet -> wallet/ismine"
|
||||
"wallet/scriptpubkeyman -> wallet/wallet -> wallet/scriptpubkeyman"
|
||||
# Dash
|
||||
"coinjoin/server -> net_processing -> coinjoin/server"
|
||||
"evo/cbtx -> evo/simplifiedmns -> evo/cbtx"
|
||||
|
@ -30,6 +30,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)"),
|
||||
]
|
||||
|
||||
def parse_function_calls(function_name, source_code):
|
||||
|
@ -16,6 +16,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…
Reference in New Issue
Block a user