Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace CAffectedKeysVisitor with descriptor based logic #14821

Changes from all commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.


Just for now

@@ -22,6 +22,7 @@
#include <policy/rbf.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <script/descriptor.h>
#include <script/script.h>
#include <shutdown.h>
#include <timedata.h>
@@ -104,67 +105,17 @@ std::string COutput::ToString() const
return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->tx->vout[i].nValue));

/** A class to identify which pubkeys a script and a keystore have in common. */
class CAffectedKeysVisitor : public boost::static_visitor<void> {
const CKeyStore &keystore;
std::vector<CKeyID> &vKeys;

* @param[in] keystoreIn The CKeyStore that is queried for the presence of a pubkey.
* @param[out] vKeysIn A vector to which a script's pubkey identifiers are appended if they are in the keystore.
CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector<CKeyID> &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {}

* Apply the visitor to each destination in a script, recursively to the redeemscript
* in the case of p2sh destinations.
* @param[in] script The CScript from which destinations are extracted.
* @post Any CKeyIDs that script and keystore have in common are appended to the visitor's vKeys.
void Process(const CScript &script) {
txnouttype type;
std::vector<CTxDestination> vDest;
int nRequired;
if (ExtractDestinations(script, type, vDest, nRequired)) {
for (const CTxDestination &dest : vDest)
boost::apply_visitor(*this, dest);

void operator()(const CKeyID &keyId) {
if (keystore.HaveKey(keyId))

void operator()(const CScriptID &scriptId) {
CScript script;
if (keystore.GetCScript(scriptId, script))

void operator()(const WitnessV0ScriptHash& scriptID)
CScriptID id;
CRIPEMD160().Write(scriptID.begin(), 32).Finalize(id.begin());
CScript script;
if (keystore.GetCScript(id, script)) {

void operator()(const WitnessV0KeyHash& keyid)
CKeyID id(keyid);
if (keystore.HaveKey(id)) {
std::vector<CKeyID> GetAffectedKeys(const CScript& spk, const SigningProvider& provider)

This comment has been minimized.

Copy link

promag Nov 28, 2018


nit, static. Could also keep some comment.

This comment has been minimized.

Copy link

instagibbs Nov 28, 2018


Could even make it more specific with the updated behavior.

This comment has been minimized.

Copy link

Empact Dec 7, 2018


nit: script_pub_key would be a more readable arg name. Granted I’m a noob but I had to check the callers.

std::vector<CScript> dummy;
FlatSigningProvider out;
InferDescriptor(spk, provider)->Expand(0, DUMMY_SIGNING_PROVIDER, dummy, out);
std::vector<CKeyID> ret;
for (const auto& entry : out.pubkeys) {

template<typename X>
void operator()(const X &none) {}
return ret;

const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
@@ -977,9 +928,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const CBlockI
// loop though all outputs
for (const CTxOut& txout: tx.vout) {
// extract addresses and check if they match with an unused keypool key
std::vector<CKeyID> vAffected;
CAffectedKeysVisitor(*this, vAffected).Process(txout.scriptPubKey);
for (const CKeyID &keyid : vAffected) {
for (const auto& keyid : GetAffectedKeys(txout.scriptPubKey, *this)) {
std::map<CKeyID, int64_t>::const_iterator mi = m_pool_key_to_index.find(keyid);
if (mi != m_pool_key_to_index.end()) {
WalletLogPrintf("%s: Detected a used keypool key, mark all keypool key up to this key as used\n", __func__);
@@ -3693,7 +3642,6 @@ void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<C

// find first block that affects those keys, if there are any left
std::vector<CKeyID> vAffected;
for (const auto& entry : mapWallet) {
// iterate over all wallet transactions...
const CWalletTx &wtx = entry.second;
@@ -3703,14 +3651,12 @@ void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<C
int nHeight = pindex->nHeight;
for (const CTxOut &txout : wtx.tx->vout) {
// iterate over all their outputs
CAffectedKeysVisitor(*this, vAffected).Process(txout.scriptPubKey);
for (const CKeyID &keyid : vAffected) {
for (const auto &keyid : GetAffectedKeys(txout.scriptPubKey, *this)) {
// ... and all their affected keys
std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid);
if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight)
rit->second = pindex;
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.