Skip to content

Commit 1d207e3

Browse files
committed
wallet: do not allow loading descriptor with an invalid ID
If the computed descriptor's ID doesn't match the wallet's DB spkm ID, return early from the loading process to prevent DB data from being modified in any post-loading procedure (e.g 'TopUp' updates the descriptor's data).
1 parent d6ee035 commit 1d207e3

File tree

2 files changed

+35
-1
lines changed

2 files changed

+35
-1
lines changed

src/wallet/test/walletload_tests.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include <wallet/test/util.h>
66
#include <wallet/wallet.h>
7+
#include <test/util/logging.h>
78
#include <test/util/setup_common.h>
89

910
#include <boost/test/unit_test.hpp>
@@ -32,7 +33,7 @@ class DummyDescriptor final : public Descriptor {
3233
void ExpandPrivate(int pos, const SigningProvider& provider, FlatSigningProvider& out) const override {}
3334
};
3435

35-
BOOST_FIXTURE_TEST_CASE(wallet_load_unknown_descriptor, TestingSetup)
36+
BOOST_FIXTURE_TEST_CASE(wallet_load_descriptors, TestingSetup)
3637
{
3738
std::unique_ptr<WalletDatabase> database = CreateMockableWalletDatabase();
3839
{
@@ -49,6 +50,33 @@ BOOST_FIXTURE_TEST_CASE(wallet_load_unknown_descriptor, TestingSetup)
4950
const std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", std::move(database)));
5051
BOOST_CHECK_EQUAL(wallet->LoadWallet(), DBErrors::UNKNOWN_DESCRIPTOR);
5152
}
53+
54+
// Test 2
55+
// Now write a valid descriptor with an invalid ID.
56+
// As the software produces another ID for the descriptor, the loading process must be aborted.
57+
database = CreateMockableWalletDatabase();
58+
59+
// Verify the error
60+
bool found = false;
61+
DebugLogHelper logHelper("The descriptor ID calculated by the wallet differs from the one in DB", [&](const std::string* s) {
62+
found = true;
63+
return false;
64+
});
65+
66+
{
67+
// Write valid descriptor with invalid ID
68+
WalletBatch batch(*database, false);
69+
std::string desc = "wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#cjjspncu";
70+
WalletDescriptor wallet_descriptor(std::make_shared<DummyDescriptor>(desc), 0, 0, 0, 0);
71+
BOOST_CHECK(batch.WriteDescriptor(uint256::ONE, wallet_descriptor));
72+
}
73+
74+
{
75+
// Now try to load the wallet and verify the error.
76+
const std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", std::move(database)));
77+
BOOST_CHECK_EQUAL(wallet->LoadWallet(), DBErrors::CORRUPT);
78+
BOOST_CHECK(found); // The error must be logged
79+
}
5280
}
5381

5482
bool HasAnyRecordOfType(WalletDatabase& db, const std::string& key)

src/wallet/walletdb.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,12 @@ static DBErrors LoadDescriptorWalletRecords(CWallet* pwallet, DatabaseBatch& bat
803803
}
804804
pwallet->LoadDescriptorScriptPubKeyMan(id, desc);
805805

806+
// Prior to doing anything with this spkm, verify ID compatibility
807+
if (id != pwallet->GetDescriptorScriptPubKeyMan(desc)->GetID()) {
808+
strErr = "The descriptor ID calculated by the wallet differs from the one in DB";
809+
return DBErrors::CORRUPT;
810+
}
811+
806812
DescriptorCache cache;
807813

808814
// Get key cache for this descriptor

0 commit comments

Comments
 (0)