Skip to content

Commit

Permalink
Merge pull request #5580 from knst/bp-descriptors-pre
Browse files Browse the repository at this point in the history
backport: bitcoin#9381, bitcoin#17219, bitcoin#18671, bitcoin#18853, bitcoin#20230, partial bitcoin#11403 (descriptor wallets preparation)
  • Loading branch information
PastaPastaPasta authored Dec 6, 2023
2 parents 8a18471 + da212ad commit ca4490a
Show file tree
Hide file tree
Showing 18 changed files with 272 additions and 192 deletions.
6 changes: 3 additions & 3 deletions src/script/descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -819,12 +819,12 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const c
auto expr = Expr(sp);
bool sorted_multi = false;
if (Func("pk", expr)) {
auto pubkey = ParsePubkey(key_exp_index, expr, ctx != ParseScriptContext::P2SH, out, error);
auto pubkey = ParsePubkey(key_exp_index, expr, true, out, error);
if (!pubkey) return nullptr;
return std::make_unique<PKDescriptor>(std::move(pubkey));
}
if (Func("pkh", expr)) {
auto pubkey = ParsePubkey(key_exp_index, expr, ctx != ParseScriptContext::P2SH, out, error);
auto pubkey = ParsePubkey(key_exp_index, expr, true, out, error);
if (!pubkey) return nullptr;
return std::make_unique<PKHDescriptor>(std::move(pubkey));
}
Expand All @@ -851,7 +851,7 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const c
return nullptr;
}
auto arg = Expr(expr);
auto pk = ParsePubkey(key_exp_index, arg, ctx != ParseScriptContext::P2SH, out, error);
auto pk = ParsePubkey(key_exp_index, arg, true, out, error);
if (!pk) return nullptr;
script_size += pk->GetSize() + 1;
providers.emplace_back(std::move(pk));
Expand Down
10 changes: 10 additions & 0 deletions src/script/signingprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,13 @@ bool FillableSigningProvider::GetCScript(const CScriptID &hash, CScript& redeemS
}
return false;
}

CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& dest)
{
// Only supports destinations which map to single public keys, i.e. P2PKH
const PKHash *pkhash = std::get_if<PKHash>(&dest);

if (pkhash != nullptr) return ToKeyID(*pkhash);

return CKeyID();
}
3 changes: 3 additions & 0 deletions src/script/signingprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,7 @@ class FillableSigningProvider : public SigningProvider
virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const override;
};

/** Return the CKeyID of the key involved in a script (if there is a unique one). */
CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& dest);

#endif // BITCOIN_SCRIPT_SIGNINGPROVIDER_H
2 changes: 1 addition & 1 deletion src/test/fuzz/key_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ FUZZ_TARGET_INIT(key_io, initialize_key_io)

const CTxDestination tx_destination = DecodeDestination(random_string);
(void)DescribeAddress(tx_destination);
// (void)GetKeyForDestination(/* store */ {}, tx_destination);
(void)GetKeyForDestination(/* store */ {}, tx_destination);
(void)GetScriptForDestination(tx_destination);
(void)IsValidDestination(tx_destination);

Expand Down
6 changes: 6 additions & 0 deletions src/test/script_standard_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@

BOOST_FIXTURE_TEST_SUITE(script_standard_tests, BasicTestingSetup)

BOOST_AUTO_TEST_CASE(dest_default_is_no_dest)
{
CTxDestination dest;
BOOST_CHECK(!IsValidDestination(dest));
}

BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
{
CKey keys[3];
Expand Down
35 changes: 19 additions & 16 deletions src/wallet/rpcdump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,6 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input.");
}
uint256 hashTx = tx.GetHash();
CWalletTx wtx(pwallet, MakeTransactionRef(std::move(tx)));

CDataStream ssMB(ParseHexV(request.params[1], "proof"), SER_NETWORK, PROTOCOL_VERSION);
CMerkleBlock merkleBlock;
Expand All @@ -329,10 +328,10 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
unsigned int txnIndex = vIndex[it - vMatch.begin()];

CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, height, merkleBlock.header.GetHash(), txnIndex);
wtx.m_confirm = confirm;

if (pwallet->IsMine(*wtx.tx)) {
pwallet->AddToWallet(wtx, false);
CTransactionRef tx_ref = MakeTransactionRef(tx);
if (pwallet->IsMine(*tx_ref)) {
pwallet->AddToWallet(std::move(tx_ref), confirm);
return NullUniValue;
}

Expand Down Expand Up @@ -908,15 +907,19 @@ UniValue dumpwallet(const JSONRPCRequest& request)
},
}.Check(request);

std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
const CWallet* const pwallet = wallet.get();
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
if (!pwallet) return NullUniValue;

LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*wallet);
CWallet& wallet = *pwallet;
LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(wallet);

LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
wallet.BlockUntilSyncedToCurrentChain();

EnsureWalletIsUnlocked(pwallet);
LOCK2(wallet.cs_wallet, spk_man.cs_KeyStore);

EnsureWalletIsUnlocked(&wallet);

fs::path filepath = request.params[0].get_str();
filepath = fs::absolute(filepath);
Expand All @@ -937,7 +940,7 @@ UniValue dumpwallet(const JSONRPCRequest& request)

std::map<CKeyID, int64_t> mapKeyBirth;
const std::map<CKeyID, int64_t>& mapKeyPool = spk_man.GetAllReserveKeys();
pwallet->GetKeyBirthTimes(mapKeyBirth);
wallet.GetKeyBirthTimes(mapKeyBirth);

std::set<CScriptID> scripts = spk_man.GetCScripts();

Expand All @@ -952,16 +955,16 @@ UniValue dumpwallet(const JSONRPCRequest& request)
// produce output
file << strprintf("# Wallet dump created by Dash Core %s\n", CLIENT_BUILD);
file << strprintf("# * Created on %s\n", FormatISO8601DateTime(GetTime()));
file << strprintf("# * Best block at time of backup was %i (%s),\n", pwallet->GetLastBlockHeight(), pwallet->GetLastBlockHash().ToString());
file << strprintf("# * Best block at time of backup was %i (%s),\n", wallet.GetLastBlockHeight(), wallet.GetLastBlockHash().ToString());
int64_t block_time = 0;
CHECK_NONFATAL(pwallet->chain().findBlock(pwallet->GetLastBlockHash(), FoundBlock().time(block_time)));
CHECK_NONFATAL(wallet.chain().findBlock(wallet.GetLastBlockHash(), FoundBlock().time(block_time)));
file << strprintf("# mined on %s\n", FormatISO8601DateTime(block_time));
file << "\n";

UniValue obj(UniValue::VOBJ);
obj.pushKV("dashcoreversion", CLIENT_BUILD);
obj.pushKV("lastblockheight", pwallet->GetLastBlockHeight());
obj.pushKV("lastblockhash", pwallet->GetLastBlockHash().ToString());
obj.pushKV("lastblockheight", wallet.GetLastBlockHeight());
obj.pushKV("lastblockhash", wallet.GetLastBlockHash().ToString());
obj.pushKV("lastblocktime", block_time);

// add the base58check encoded extended master if the wallet uses HD
Expand Down Expand Up @@ -1012,7 +1015,7 @@ UniValue dumpwallet(const JSONRPCRequest& request)
CKey key;
if (spk_man.GetKey(keyid, key)) {
file << strprintf("%s %s ", EncodeSecret(key), strTime);
const auto* address_book_entry = pwallet->FindAddressBookEntry(pkhash);
const auto* address_book_entry = wallet.FindAddressBookEntry(pkhash);
if (address_book_entry) {
file << strprintf("label=%s", EncodeDumpString(address_book_entry->GetLabel()));
} else if (mapKeyPool.count(keyid)) {
Expand Down
12 changes: 4 additions & 8 deletions src/wallet/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,10 +258,6 @@ 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()) {
Expand Down Expand Up @@ -1632,7 +1628,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
UniValue transactions(UniValue::VARR);

for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
CWalletTx tx = pairWtx.second;
const CWalletTx& tx = pairWtx.second;

if (depth == -1 || abs(tx.GetDepthInMainChain()) < depth) {
ListTransactions(pwallet, tx, 0, true, transactions, filter, nullptr /* filter_label */);
Expand Down Expand Up @@ -2560,9 +2556,9 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
if (spk_man) {
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("keypoolsize", (int64_t)pwallet->KeypoolCountExternalKeys());
obj.pushKV("keypoolsize_hd_internal", (int64_t)(pwallet->KeypoolCountInternalKeys()));
obj.pushKV("keys_left", pwallet->nKeysLeftSinceAutoBackup);
if (pwallet->IsCrypted())
obj.pushKV("unlocked_until", pwallet->nRelockTime);
Expand Down Expand Up @@ -3833,12 +3829,12 @@ UniValue getaddressinfo(const JSONRPCRequest& request)

ScriptPubKeyMan* spk_man = pwallet->GetScriptPubKeyMan(scriptPubKey);
if (spk_man) {
const PKHash *pkhash = std::get_if<PKHash>(&dest);
if (const CKeyMetadata* meta = spk_man->GetMetadata(dest)) {
ret.pushKV("timestamp", meta->nCreateTime);
CHDChain hdChainCurrent;
LegacyScriptPubKeyMan* legacy_spk_man = pwallet->GetLegacyScriptPubKeyMan();
if (legacy_spk_man != nullptr) {
const PKHash *pkhash = std::get_if<PKHash>(&dest);
if (pkhash && legacy_spk_man->HaveHDKey(ToKeyID(*pkhash), hdChainCurrent)) {
ret.pushKV("hdchainid", hdChainCurrent.GetID().GetHex());
}
Expand Down
8 changes: 4 additions & 4 deletions src/wallet/scriptpubkeyman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ bool LegacyScriptPubKeyMan::GetNewDestination(CTxDestination& dest, std::string&
// Generate a new key that is added to wallet
CPubKey new_key;
if (!GetKeyFromPool(new_key, false)) {
error = "Error: Keypool ran out, please call keypoolrefill first";
error = _("Error: Keypool ran out, please call keypoolrefill first").translated;
return false;
}
//LearnRelatedScripts(new_key);
Expand Down Expand Up @@ -749,9 +749,9 @@ const CKeyMetadata* LegacyScriptPubKeyMan::GetMetadata(const CTxDestination& des
{
LOCK(cs_KeyStore);

const PKHash *pkhash = std::get_if<PKHash>(&dest);
if (pkhash != nullptr && !ToKeyID(*pkhash).IsNull()) {
auto it = mapKeyMetadata.find(ToKeyID(*pkhash));
CKeyID key_id = GetKeyForDestination(*this, dest);
if (!key_id.IsNull()) {
auto it = mapKeyMetadata.find(key_id);
if (it != mapKeyMetadata.end()) {
return &it->second;
}
Expand Down
9 changes: 2 additions & 7 deletions src/wallet/test/coinselector_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ BOOST_FIXTURE_TEST_SUITE(coinselector_tests, WalletTestingSetup)
// we repeat those tests this many times and only complain if all iterations of the test fail
#define RANDOM_REPEATS 5

std::vector<std::unique_ptr<CWalletTx>> wtxn;

typedef std::set<CInputCoin> CoinSet;

static std::vector<COutput> vCoins;
Expand Down Expand Up @@ -76,16 +74,14 @@ static void add_coin(CWallet& wallet, const CAmount& nValue, int nAge = 6*24, bo
// so stop vin being empty, and cache a non-zero Debit to fake out IsFromMe()
tx.vin.resize(1);
}
std::unique_ptr<CWalletTx> wtx = std::make_unique<CWalletTx>(&wallet, MakeTransactionRef(std::move(tx)));
CWalletTx* wtx = wallet.AddToWallet(MakeTransactionRef(std::move(tx)), /* confirm= */ {});
if (fIsFromMe)
{
wtx->m_amounts[CWalletTx::DEBIT].Set(ISMINE_SPENDABLE, 1);
wtx->m_is_cache_empty = false;
}
COutput output(wtx.get(), nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
COutput output(wtx, nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
vCoins.push_back(output);
wallet.AddToWallet(*wtx.get());
wtxn.emplace_back(std::move(wtx));
}
static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0, bool spendable = false)
{
Expand All @@ -95,7 +91,6 @@ static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = fa
static void empty_wallet(void)
{
vCoins.clear();
wtxn.clear();
balance = 0;
}

Expand Down
6 changes: 2 additions & 4 deletions src/wallet/test/psbt_wallet_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,12 @@ BOOST_AUTO_TEST_CASE(psbt_updater_test)
CDataStream s_prev_tx1(ParseHex("0200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000"), SER_NETWORK, PROTOCOL_VERSION);
CTransactionRef prev_tx1;
s_prev_tx1 >> prev_tx1;
CWalletTx prev_wtx1(&m_wallet, prev_tx1);
m_wallet.mapWallet.emplace(prev_wtx1.GetHash(), std::move(prev_wtx1));
m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx1->GetHash()), std::forward_as_tuple(&m_wallet, prev_tx1));

CDataStream s_prev_tx2(ParseHex("0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000"), SER_NETWORK, PROTOCOL_VERSION);
CTransactionRef prev_tx2;
s_prev_tx2 >> prev_tx2;
CWalletTx prev_wtx2(&m_wallet, prev_tx2);
m_wallet.mapWallet.emplace(prev_wtx2.GetHash(), std::move(prev_wtx2));
m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx2->GetHash()), std::forward_as_tuple(&m_wallet, prev_tx2));

// Add scripts
CScript rs1;
Expand Down
33 changes: 15 additions & 18 deletions src/wallet/test/wallet_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,17 +264,21 @@ 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>(m_node.chain.get(), "", CreateDummyWalletDatabase());
auto spk_man = wallet->GetOrCreateLegacyScriptPubKeyMan();
LOCK2(wallet->cs_wallet, spk_man->cs_KeyStore);
spk_man->mapKeyMetadata[coinbaseKey.GetPubKey().GetID()].nCreateTime = KEY_TIME;
spk_man->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
{
auto spk_man = wallet->GetOrCreateLegacyScriptPubKeyMan();
LOCK2(wallet->cs_wallet, spk_man->cs_KeyStore);
spk_man->mapKeyMetadata[coinbaseKey.GetPubKey().GetID()].nCreateTime = KEY_TIME;
spk_man->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());

AddWallet(wallet);
wallet->SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
}
CoreContext context{m_node};
JSONRPCRequest request(context);

request.params.setArray();
request.params.push_back(backup_file);
AddWallet(wallet);
wallet->SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());

::dumpwallet(request);
RemoveWallet(wallet, std::nullopt);
}
Expand Down Expand Up @@ -415,6 +419,7 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
static int64_t AddTx(ChainstateManager& chainman, CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64_t blockTime)
{
CMutableTransaction tx;
CWalletTx::Confirmation confirm;
tx.nLockTime = lockTime;
SetMockTime(mockTime);
CBlockIndex* block = nullptr;
Expand All @@ -426,23 +431,15 @@ static int64_t AddTx(ChainstateManager& chainman, CWallet& wallet, uint32_t lock
block = inserted.first->second;
block->nTime = blockTime;
block->phashBlock = &hash;
confirm = {CWalletTx::Status::CONFIRMED, block->nHeight, hash, 0};
}

CWalletTx wtx(&wallet, MakeTransactionRef(tx));
LOCK(wallet.cs_wallet);
// If transaction is already in map, to avoid inconsistencies, unconfirmation
// is needed before confirm again with different block.
std::map<uint256, CWalletTx>::iterator it = wallet.mapWallet.find(wtx.GetHash());
if (it != wallet.mapWallet.end()) {
return wallet.AddToWallet(MakeTransactionRef(tx), confirm, [&](CWalletTx& wtx, bool /* new_tx */) {
wtx.setUnconfirmed();
wallet.AddToWallet(wtx);
}
if (block) {
CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, block->nHeight, block->GetBlockHash(), 0);
wtx.m_confirm = confirm;
}
wallet.AddToWallet(wtx);
return wallet.mapWallet.at(wtx.GetHash()).nTimeSmart;
return true;
})->nTimeSmart;
}

// Simple test to verify assignment of CWalletTx::nSmartTime value. Could be
Expand Down
Loading

0 comments on commit ca4490a

Please sign in to comment.