Refactor: Allow LegacyScriptPubKeyMan to be null

In CWallet::LoadWallet, use this to detect and empty wallet with no keys

This commit does not change behavior.
This commit is contained in:
Andrew Chow 2019-10-07 14:11:34 -04:00
parent fadc08ad94
commit eb81fc3ee5
15 changed files with 86 additions and 37 deletions

View File

@ -31,7 +31,8 @@ static void CoinSelection(benchmark::State& state)
{ {
NodeContext node; NodeContext node;
auto chain = interfaces::MakeChain(node); auto chain = interfaces::MakeChain(node);
const CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
wallet.SetupLegacyScriptPubKeyMan();
std::vector<std::unique_ptr<CWalletTx>> wtxs; std::vector<std::unique_ptr<CWalletTx>> wtxs;
LOCK(wallet.cs_wallet); LOCK(wallet.cs_wallet);
@ -64,7 +65,7 @@ static void CoinSelection(benchmark::State& state)
typedef std::set<CInputCoin> CoinSet; typedef std::set<CInputCoin> CoinSet;
static NodeContext testNode; static NodeContext testNode;
static auto testChain = interfaces::MakeChain(testNode); static auto testChain = interfaces::MakeChain(testNode);
static const CWallet testWallet(testChain.get(), WalletLocation(), WalletDatabase::CreateDummy()); static CWallet testWallet(testChain.get(), WalletLocation(), WalletDatabase::CreateDummy());
std::vector<std::unique_ptr<CWalletTx>> wtxn; std::vector<std::unique_ptr<CWalletTx>> wtxn;
// Copied from src/wallet/test/coinselector_tests.cpp // Copied from src/wallet/test/coinselector_tests.cpp
@ -93,6 +94,7 @@ static CAmount make_hard_case(int utxos, std::vector<OutputGroup>& utxo_pool)
static void BnBExhaustion(benchmark::State& state) static void BnBExhaustion(benchmark::State& state)
{ {
// Setup // Setup
testWallet.SetupLegacyScriptPubKeyMan();
std::vector<OutputGroup> utxo_pool; std::vector<OutputGroup> utxo_pool;
CoinSet selection; CoinSet selection;
CAmount value_ret = 0; CAmount value_ret = 0;

View File

@ -20,6 +20,7 @@ static void WalletBalance(benchmark::State& state, const bool set_dirty, const b
std::unique_ptr<interfaces::Chain> chain = interfaces::MakeChain(node); std::unique_ptr<interfaces::Chain> chain = interfaces::MakeChain(node);
CWallet wallet{chain.get(), WalletLocation(), WalletDatabase::CreateMock()}; CWallet wallet{chain.get(), WalletLocation(), WalletDatabase::CreateMock()};
{ {
wallet.SetupLegacyScriptPubKeyMan();
bool first_run; bool first_run;
if (wallet.LoadWallet(first_run) != DBErrors::LOAD_OK) assert(false); if (wallet.LoadWallet(first_run) != DBErrors::LOAD_OK) assert(false);
wallet.handleNotifications(); wallet.handleNotifications();

View File

@ -59,6 +59,7 @@ void TestAddAddressesToSendBook(interfaces::Node& node)
{ {
TestChain100Setup test; TestChain100Setup test;
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), WalletLocation(), WalletDatabase::CreateMock()); std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), WalletLocation(), WalletDatabase::CreateMock());
wallet->SetupLegacyScriptPubKeyMan();
bool firstRun; bool firstRun;
wallet->LoadWallet(firstRun); wallet->LoadWallet(firstRun);

View File

@ -143,7 +143,7 @@ void TestGUI(interfaces::Node& node)
bool firstRun; bool firstRun;
wallet->LoadWallet(firstRun); wallet->LoadWallet(firstRun);
{ {
auto spk_man = wallet->GetLegacyScriptPubKeyMan(); auto spk_man = wallet->GetOrCreateLegacyScriptPubKeyMan();
auto locked_chain = wallet->chain().lock(); auto locked_chain = wallet->chain().lock();
LOCK2(wallet->cs_wallet, spk_man->cs_KeyStore); LOCK2(wallet->cs_wallet, spk_man->cs_KeyStore);
wallet->SetAddressBook(GetDestinationForKey(test.coinbaseKey.GetPubKey(), wallet->m_default_address_type), "", "receive"); wallet->SetAddressBook(GetDestinationForKey(test.coinbaseKey.GetPubKey(), wallet->m_default_address_type), "", "receive");

View File

@ -125,7 +125,7 @@ UniValue importprivkey(const JSONRPCRequest& request)
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled"); throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled");
} }
EnsureLegacyScriptPubKeyMan(*wallet); EnsureLegacyScriptPubKeyMan(*wallet, true);
WalletRescanReserver reserver(pwallet); WalletRescanReserver reserver(pwallet);
bool fRescan = true; bool fRescan = true;
@ -253,7 +253,7 @@ UniValue importaddress(const JSONRPCRequest& request)
}, },
}.Check(request); }.Check(request);
EnsureLegacyScriptPubKeyMan(*pwallet); EnsureLegacyScriptPubKeyMan(*pwallet, true);
std::string strLabel; std::string strLabel;
if (!request.params[1].isNull()) if (!request.params[1].isNull())
@ -454,7 +454,7 @@ UniValue importpubkey(const JSONRPCRequest& request)
}, },
}.Check(request); }.Check(request);
EnsureLegacyScriptPubKeyMan(*wallet); EnsureLegacyScriptPubKeyMan(*wallet, true);
std::string strLabel; std::string strLabel;
if (!request.params[1].isNull()) if (!request.params[1].isNull())
@ -538,7 +538,7 @@ UniValue importwallet(const JSONRPCRequest& request)
}, },
}.Check(request); }.Check(request);
EnsureLegacyScriptPubKeyMan(*wallet); EnsureLegacyScriptPubKeyMan(*wallet, true);
if (pwallet->chain().havePruned()) { if (pwallet->chain().havePruned()) {
// Exit early and print an error. // Exit early and print an error.
@ -1334,7 +1334,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ}); RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ});
EnsureLegacyScriptPubKeyMan(*wallet); EnsureLegacyScriptPubKeyMan(*wallet, true);
const UniValue& requests = mainRequest.params[0]; const UniValue& requests = mainRequest.params[0];

View File

@ -124,9 +124,13 @@ void EnsureWalletIsUnlocked(const CWallet* pwallet)
} }
} }
LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet) // also_create should only be set to true only when the RPC is expected to add things to a blank wallet and make it no longer blank
LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create)
{ {
LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan(); LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan();
if (!spk_man && also_create) {
spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
}
if (!spk_man) { if (!spk_man) {
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command"); throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
} }
@ -4003,7 +4007,7 @@ UniValue sethdseed(const JSONRPCRequest& request)
}, },
}.Check(request); }.Check(request);
LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet); LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet, true);
if (pwallet->chain().isInitialBlockDownload()) { if (pwallet->chain().isInitialBlockDownload()) {
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Cannot set a new HD seed while still in Initial Block Download"); throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Cannot set a new HD seed while still in Initial Block Download");

View File

@ -41,7 +41,7 @@ std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& reques
std::string HelpRequiringPassphrase(const CWallet*); std::string HelpRequiringPassphrase(const CWallet*);
void EnsureWalletIsUnlocked(const CWallet*); void EnsureWalletIsUnlocked(const CWallet*);
bool EnsureWalletIsAvailable(const CWallet*, bool avoidException); bool EnsureWalletIsAvailable(const CWallet*, bool avoidException);
LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet); LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create = false);
UniValue getaddressinfo(const JSONRPCRequest& request); UniValue getaddressinfo(const JSONRPCRequest& request);
UniValue signrawtransactionwithwallet(const JSONRPCRequest& request); UniValue signrawtransactionwithwallet(const JSONRPCRequest& request);

View File

@ -136,6 +136,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
{ {
LOCK(testWallet.cs_wallet); LOCK(testWallet.cs_wallet);
testWallet.SetupLegacyScriptPubKeyMan();
// Setup // Setup
std::vector<CInputCoin> utxo_pool; std::vector<CInputCoin> utxo_pool;
@ -278,6 +279,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
std::unique_ptr<CWallet> wallet = MakeUnique<CWallet>(m_chain.get(), WalletLocation(), WalletDatabase::CreateMock()); std::unique_ptr<CWallet> wallet = MakeUnique<CWallet>(m_chain.get(), WalletLocation(), WalletDatabase::CreateMock());
bool firstRun; bool firstRun;
wallet->LoadWallet(firstRun); wallet->LoadWallet(firstRun);
wallet->SetupLegacyScriptPubKeyMan();
LOCK(wallet->cs_wallet); LOCK(wallet->cs_wallet);
add_coin(*wallet, 5 * CENT, 6 * 24, false, 0, true); add_coin(*wallet, 5 * CENT, 6 * 24, false, 0, true);
add_coin(*wallet, 3 * CENT, 6 * 24, false, 0, true); add_coin(*wallet, 3 * CENT, 6 * 24, false, 0, true);
@ -299,6 +301,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
bool bnb_used; bool bnb_used;
LOCK(testWallet.cs_wallet); LOCK(testWallet.cs_wallet);
testWallet.SetupLegacyScriptPubKeyMan();
// test multiple times to allow for differences in the shuffle order // test multiple times to allow for differences in the shuffle order
for (int i = 0; i < RUN_TESTS; i++) for (int i = 0; i < RUN_TESTS; i++)
@ -578,6 +581,7 @@ BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
bool bnb_used; bool bnb_used;
LOCK(testWallet.cs_wallet); LOCK(testWallet.cs_wallet);
testWallet.SetupLegacyScriptPubKeyMan();
empty_wallet(); empty_wallet();
@ -596,6 +600,8 @@ BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
// Tests that with the ideal conditions, the coin selector will always be able to find a solution that can pay the target value // Tests that with the ideal conditions, the coin selector will always be able to find a solution that can pay the target value
BOOST_AUTO_TEST_CASE(SelectCoins_test) BOOST_AUTO_TEST_CASE(SelectCoins_test)
{ {
testWallet.SetupLegacyScriptPubKeyMan();
// Random generator stuff // Random generator stuff
std::default_random_engine generator; std::default_random_engine generator;
std::exponential_distribution<double> distribution (100); std::exponential_distribution<double> distribution (100);

View File

@ -36,6 +36,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PK compressed // P2PK compressed
{ {
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForRawPubKey(pubkeys[0]); scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
@ -52,6 +53,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PK uncompressed // P2PK uncompressed
{ {
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey); scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
@ -68,6 +70,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PKH compressed // P2PKH compressed
{ {
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0])); scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0]));
@ -84,6 +87,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PKH uncompressed // P2PKH uncompressed
{ {
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey)); scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey));
@ -100,6 +104,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2SH // P2SH
{ {
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0])); CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0]));
@ -123,6 +128,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// (P2PKH inside) P2SH inside P2SH (invalid) // (P2PKH inside) P2SH inside P2SH (invalid)
{ {
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
CScript redeemscript_inner = GetScriptForDestination(PKHash(pubkeys[0])); CScript redeemscript_inner = GetScriptForDestination(PKHash(pubkeys[0]));
@ -140,6 +146,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// (P2PKH inside) P2SH inside P2WSH (invalid) // (P2PKH inside) P2SH inside P2WSH (invalid)
{ {
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
CScript redeemscript = GetScriptForDestination(PKHash(pubkeys[0])); CScript redeemscript = GetScriptForDestination(PKHash(pubkeys[0]));
@ -157,6 +164,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WPKH inside P2WSH (invalid) // P2WPKH inside P2WSH (invalid)
{ {
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
CScript witnessscript = GetScriptForDestination(WitnessV0KeyHash(PKHash(pubkeys[0]))); CScript witnessscript = GetScriptForDestination(WitnessV0KeyHash(PKHash(pubkeys[0])));
@ -172,6 +180,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// (P2PKH inside) P2WSH inside P2WSH (invalid) // (P2PKH inside) P2WSH inside P2WSH (invalid)
{ {
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
CScript witnessscript_inner = GetScriptForDestination(PKHash(pubkeys[0])); CScript witnessscript_inner = GetScriptForDestination(PKHash(pubkeys[0]));
@ -189,6 +198,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WPKH compressed // P2WPKH compressed
{ {
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0])); BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@ -203,6 +213,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WPKH uncompressed // P2WPKH uncompressed
{ {
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey)); BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
@ -221,6 +232,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// scriptPubKey multisig // scriptPubKey multisig
{ {
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]}); scriptPubKey = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
@ -251,6 +263,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2SH multisig // P2SH multisig
{ {
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey)); BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1])); BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
@ -271,6 +284,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WSH multisig with compressed keys // P2WSH multisig with compressed keys
{ {
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0])); BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1])); BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
@ -296,6 +310,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WSH multisig with uncompressed key // P2WSH multisig with uncompressed key
{ {
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey)); BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1])); BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
@ -321,6 +336,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WSH multisig wrapped in P2SH // P2WSH multisig wrapped in P2SH
{ {
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]}); CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
@ -347,6 +363,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// OP_RETURN // OP_RETURN
{ {
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0])); BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@ -360,6 +377,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// witness unspendable // witness unspendable
{ {
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0])); BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@ -373,6 +391,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// witness unknown // witness unknown
{ {
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0])); BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@ -386,6 +405,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// Nonstandard // Nonstandard
{ {
CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore); LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0])); BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));

View File

@ -16,7 +16,7 @@ BOOST_FIXTURE_TEST_SUITE(psbt_wallet_tests, WalletTestingSetup)
BOOST_AUTO_TEST_CASE(psbt_updater_test) BOOST_AUTO_TEST_CASE(psbt_updater_test)
{ {
auto spk_man = m_wallet.GetLegacyScriptPubKeyMan(); auto spk_man = m_wallet.GetOrCreateLegacyScriptPubKeyMan();
LOCK2(m_wallet.cs_wallet, spk_man->cs_KeyStore); LOCK2(m_wallet.cs_wallet, spk_man->cs_KeyStore);
// Create prevtxs and add to wallet // Create prevtxs and add to wallet

View File

@ -28,7 +28,7 @@ BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup)
static void AddKey(CWallet& wallet, const CKey& key) static void AddKey(CWallet& wallet, const CKey& key)
{ {
auto spk_man = wallet.GetLegacyScriptPubKeyMan(); auto spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
LOCK2(wallet.cs_wallet, spk_man->cs_KeyStore); LOCK2(wallet.cs_wallet, spk_man->cs_KeyStore);
spk_man->AddKeyPubKey(key, key.GetPubKey()); spk_man->AddKeyPubKey(key, key.GetPubKey());
} }
@ -151,6 +151,7 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup)
// after. // after.
{ {
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
wallet->SetupLegacyScriptPubKeyMan();
AddWallet(wallet); AddWallet(wallet);
UniValue keys; UniValue keys;
keys.setArray(); keys.setArray();
@ -215,7 +216,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
// Import key into wallet and call dumpwallet to create backup file. // Import key into wallet and call dumpwallet to create backup file.
{ {
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
auto spk_man = wallet->GetLegacyScriptPubKeyMan(); auto spk_man = wallet->GetOrCreateLegacyScriptPubKeyMan();
LOCK2(wallet->cs_wallet, spk_man->cs_KeyStore); LOCK2(wallet->cs_wallet, spk_man->cs_KeyStore);
spk_man->mapKeyMetadata[coinbaseKey.GetPubKey().GetID()].nCreateTime = KEY_TIME; spk_man->mapKeyMetadata[coinbaseKey.GetPubKey().GetID()].nCreateTime = KEY_TIME;
spk_man->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey()); spk_man->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
@ -232,6 +233,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
// were scanned, and no prior blocks were scanned. // were scanned, and no prior blocks were scanned.
{ {
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
wallet->SetupLegacyScriptPubKeyMan();
JSONRPCRequest request; JSONRPCRequest request;
request.params.setArray(); request.params.setArray();
@ -265,7 +267,7 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
auto chain = interfaces::MakeChain(node); auto chain = interfaces::MakeChain(node);
CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
auto spk_man = wallet.GetLegacyScriptPubKeyMan(); auto spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
CWalletTx wtx(&wallet, m_coinbase_txns.back()); CWalletTx wtx(&wallet, m_coinbase_txns.back());
auto locked_chain = chain->lock(); auto locked_chain = chain->lock();
@ -280,7 +282,7 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
// cache the current immature credit amount, which is 0. // cache the current immature credit amount, which is 0.
BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(), 0); BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(), 0);
// Invalidate the cached vanue, add the key, and make sure a new immature // Invalidate the cached value, add the key, and make sure a new immature
// credit amount is calculated. // credit amount is calculated.
wtx.MarkDirty(); wtx.MarkDirty();
BOOST_CHECK(spk_man->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey())); BOOST_CHECK(spk_man->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey()));
@ -415,7 +417,7 @@ BOOST_AUTO_TEST_CASE(WatchOnlyPubKeys)
{ {
CKey key; CKey key;
CPubKey pubkey; CPubKey pubkey;
LegacyScriptPubKeyMan* spk_man = m_wallet.GetLegacyScriptPubKeyMan(); LegacyScriptPubKeyMan* spk_man = m_wallet.GetOrCreateLegacyScriptPubKeyMan();
BOOST_CHECK(!spk_man->HaveWatchOnly()); BOOST_CHECK(!spk_man->HaveWatchOnly());
@ -577,6 +579,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
NodeContext node; NodeContext node;
auto chain = interfaces::MakeChain(node); auto chain = interfaces::MakeChain(node);
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
wallet->SetupLegacyScriptPubKeyMan();
wallet->SetMinVersion(FEATURE_LATEST); wallet->SetMinVersion(FEATURE_LATEST);
wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS); wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
BOOST_CHECK(!wallet->TopUpKeyPool(1000)); BOOST_CHECK(!wallet->TopUpKeyPool(1000));

View File

@ -2993,10 +2993,9 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
} }
} }
// This wallet is in its first run if there are no ScriptPubKeyMans and it isn't blank or no privkeys
{ {
LOCK(cs_KeyStore); fFirstRunRet = !m_spk_man
// This wallet is in its first run if all of these are empty
fFirstRunRet = mapKeys.empty() && mapCryptedKeys.empty() && mapWatchKeys.empty() && setWatchOnly.empty() && mapScripts.empty()
&& !IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET); && !IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET);
} }
@ -3727,6 +3726,10 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
walletInstance->SetMinVersion(FEATURE_LATEST); walletInstance->SetMinVersion(FEATURE_LATEST);
walletInstance->SetWalletFlags(wallet_creation_flags, false); walletInstance->SetWalletFlags(wallet_creation_flags, false);
// Always create LegacyScriptPubKeyMan for now
walletInstance->SetupLegacyScriptPubKeyMan();
if (!(wallet_creation_flags & (WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET))) { if (!(wallet_creation_flags & (WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET))) {
LOCK(walletInstance->cs_wallet); LOCK(walletInstance->cs_wallet);
if (auto spk_man = walletInstance->m_spk_man.get()) { if (auto spk_man = walletInstance->m_spk_man.get()) {
@ -4121,6 +4124,17 @@ LegacyScriptPubKeyMan* CWallet::GetLegacyScriptPubKeyMan() const
return m_spk_man.get(); return m_spk_man.get();
} }
LegacyScriptPubKeyMan* CWallet::GetOrCreateLegacyScriptPubKeyMan()
{
SetupLegacyScriptPubKeyMan();
return GetLegacyScriptPubKeyMan();
}
void CWallet::SetupLegacyScriptPubKeyMan()
{
if (!m_spk_man) m_spk_man = MakeUnique<LegacyScriptPubKeyMan>(*this);
}
const CKeyingMaterial& CWallet::GetEncryptionKey() const const CKeyingMaterial& CWallet::GetEncryptionKey() const
{ {
return vMasterKey; return vMasterKey;

View File

@ -1140,19 +1140,17 @@ public:
const SigningProvider* GetSigningProvider(const CScript& script, SignatureData& sigdata) const; const SigningProvider* GetSigningProvider(const CScript& script, SignatureData& sigdata) const;
LegacyScriptPubKeyMan* GetLegacyScriptPubKeyMan() const; LegacyScriptPubKeyMan* GetLegacyScriptPubKeyMan() const;
LegacyScriptPubKeyMan* GetOrCreateLegacyScriptPubKeyMan();
//! Make a LegacyScriptPubKeyMan and set it for all types, internal, and external.
void SetupLegacyScriptPubKeyMan();
const CKeyingMaterial& GetEncryptionKey() const override; const CKeyingMaterial& GetEncryptionKey() const override;
bool HasEncryptionKeys() const override; bool HasEncryptionKeys() const override;
// Temporary LegacyScriptPubKeyMan accessors and aliases. // Temporary LegacyScriptPubKeyMan accessors and aliases.
friend class LegacyScriptPubKeyMan; friend class LegacyScriptPubKeyMan;
std::unique_ptr<LegacyScriptPubKeyMan> m_spk_man = MakeUnique<LegacyScriptPubKeyMan>(*this); std::unique_ptr<LegacyScriptPubKeyMan> m_spk_man;
RecursiveMutex& 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;
/** Get last block processed height */ /** Get last block processed height */
int GetLastBlockHeight() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) int GetLastBlockHeight() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)

View File

@ -251,7 +251,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
char fYes; char fYes;
ssValue >> fYes; ssValue >> fYes;
if (fYes == '1') { if (fYes == '1') {
pwallet->GetLegacyScriptPubKeyMan()->LoadWatchOnly(script); pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadWatchOnly(script);
} }
} else if (strType == DBKeys::KEY) { } else if (strType == DBKeys::KEY) {
CPubKey vchPubKey; CPubKey vchPubKey;
@ -303,7 +303,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
strErr = "Error reading wallet database: CPrivKey corrupt"; strErr = "Error reading wallet database: CPrivKey corrupt";
return false; return false;
} }
if (!pwallet->GetLegacyScriptPubKeyMan()->LoadKey(key, vchPubKey)) if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKey(key, vchPubKey))
{ {
strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadKey failed"; strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadKey failed";
return false; return false;
@ -334,7 +334,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
ssValue >> vchPrivKey; ssValue >> vchPrivKey;
wss.nCKeys++; wss.nCKeys++;
if (!pwallet->GetLegacyScriptPubKeyMan()->LoadCryptedKey(vchPubKey, vchPrivKey)) if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadCryptedKey(vchPubKey, vchPrivKey))
{ {
strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadCryptedKey failed"; strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadCryptedKey failed";
return false; return false;
@ -346,14 +346,14 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
CKeyMetadata keyMeta; CKeyMetadata keyMeta;
ssValue >> keyMeta; ssValue >> keyMeta;
wss.nKeyMeta++; wss.nKeyMeta++;
pwallet->GetLegacyScriptPubKeyMan()->LoadKeyMetadata(vchPubKey.GetID(), keyMeta); pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKeyMetadata(vchPubKey.GetID(), keyMeta);
} else if (strType == DBKeys::WATCHMETA) { } else if (strType == DBKeys::WATCHMETA) {
CScript script; CScript script;
ssKey >> script; ssKey >> script;
CKeyMetadata keyMeta; CKeyMetadata keyMeta;
ssValue >> keyMeta; ssValue >> keyMeta;
wss.nKeyMeta++; wss.nKeyMeta++;
pwallet->GetLegacyScriptPubKeyMan()->LoadScriptMetadata(CScriptID(script), keyMeta); pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadScriptMetadata(CScriptID(script), keyMeta);
} else if (strType == DBKeys::DEFAULTKEY) { } else if (strType == DBKeys::DEFAULTKEY) {
// We don't want or need the default key, but if there is one set, // 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 // we want to make sure that it is valid so that we can detect corruption
@ -369,13 +369,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
CKeyPool keypool; CKeyPool keypool;
ssValue >> keypool; ssValue >> keypool;
pwallet->GetLegacyScriptPubKeyMan()->LoadKeyPool(nIndex, keypool); pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKeyPool(nIndex, keypool);
} else if (strType == DBKeys::CSCRIPT) { } else if (strType == DBKeys::CSCRIPT) {
uint160 hash; uint160 hash;
ssKey >> hash; ssKey >> hash;
CScript script; CScript script;
ssValue >> script; ssValue >> script;
if (!pwallet->GetLegacyScriptPubKeyMan()->LoadCScript(script)) if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadCScript(script))
{ {
strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadCScript failed"; strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadCScript failed";
return false; return false;
@ -391,7 +391,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
} else if (strType == DBKeys::HDCHAIN) { } else if (strType == DBKeys::HDCHAIN) {
CHDChain chain; CHDChain chain;
ssValue >> chain; ssValue >> chain;
pwallet->GetLegacyScriptPubKeyMan()->SetHDChain(chain, true); pwallet->GetOrCreateLegacyScriptPubKeyMan()->SetHDChain(chain, true);
} else if (strType == DBKeys::FLAGS) { } else if (strType == DBKeys::FLAGS) {
uint64_t flags; uint64_t flags;
ssValue >> flags; ssValue >> flags;
@ -515,7 +515,7 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
// nTimeFirstKey is only reliable if all keys have metadata // nTimeFirstKey is only reliable if all keys have metadata
if ((wss.nKeys + wss.nCKeys + wss.nWatchKeys) != wss.nKeyMeta) { if ((wss.nKeys + wss.nCKeys + wss.nWatchKeys) != wss.nKeyMeta) {
auto spk_man = pwallet->GetLegacyScriptPubKeyMan(); auto spk_man = pwallet->GetOrCreateLegacyScriptPubKeyMan();
if (spk_man) { if (spk_man) {
LOCK(spk_man->cs_KeyStore); LOCK(spk_man->cs_KeyStore);
spk_man->UpdateTimeFirstKey(1); spk_man->UpdateTimeFirstKey(1);

View File

@ -38,7 +38,7 @@ static std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::
wallet_instance->SetMinVersion(FEATURE_HD_SPLIT); wallet_instance->SetMinVersion(FEATURE_HD_SPLIT);
// generate a new HD seed // generate a new HD seed
auto spk_man = wallet_instance->GetLegacyScriptPubKeyMan(); auto spk_man = wallet_instance->GetOrCreateLegacyScriptPubKeyMan();
CPubKey seed = spk_man->GenerateNewSeed(); CPubKey seed = spk_man->GenerateNewSeed();
spk_man->SetHDSeed(seed); spk_man->SetHDSeed(seed);