3

When the wallet examines a transaction for relevance what does it do exactly with that transaction's output scripts and what is that data compared to? Does the wallet database store a table of all the actual output scripts (i.e. witness programs) derived from its keypool?

I'm especially curious about scanning tx inputs to recognize coins we have spent. Do we only check outpoints stored in the walletdb? Or do we go as far as inspecting input scripts and witness stacks for our own public keys?

3 Answers 3

4

Does the wallet database store a table of all the actual output scripts (i.e. witness programs) derived from its keypool?

Kind of.

For descriptor wallets, the set of all scriptPubKeys (up to the keypool limit for each descriptor) is generated and held in memory. When determining whether a transaction output belongs to the wallet, the wallet checks whether the output's scriptPubKey is in that set. If it is, then the output belongs to the wallet.

One thing to note though is that this scriptPubKey set is not stored in the database. Once the wallet is unloaded, the set is forgotten. It will be recomputed every time the wallet is loaded.

For legacy wallets, it's a lot more complicated. It will determine the type of script and then do lookups for scripts and keys in the wallet depending on the type. For the most part, it does boil down to a finite set of scripts, but this can actually be a very large set that contains a lot of scripts that you might not expect it to.

I'm especially curious about scanning tx inputs to recognize coins we have spent. Do we only check outpoints stored in the walletdb?

Yes. For inputs, the wallet will only check to see if the referenced output exists in the wallet and that output belongs to the wallet. This also means that rescanning must be done serially. If the wallet scanned a transaction that contains a spend of an output that belongs to it, but it hadn't scanned the transaction creating that output yet, then it would not detect the spending transaction.

One unexpected aspect of the Bitcoin Core wallet is that it doesn't explicitly mark which outputs actually belong to it. If it needs to know whether an output belongs to the wallet, it will check the scriptPubKey against the in-memory scriptPubKey set. Similarly, it doesn't explicitly permanently mark outputs as being spent. If you were to remove the spending transaction from your wallet using removeprunedfunds, the output would suddenly appear to be unspent and your wallet could make a transaction spending it. Of course, this would also make an invalid transaction.

5

Does the wallet database store a table of all the actual output scripts (i.e. witness programs) derived from its keypool?

Yes, exactly. The descriptors (and for legacy wallet, legacy data) is expanded into a set of scriptPubKeys to look for.

  • A transaction output is ours if its scriptPubKey matches an entry in that set.
  • A transaction input is ours if it spends an output that is ours.
  • A transaction is ours if it has at least one input or output that is ours.

Note that this does not require examining witness data for inputs. It suffices to look for spends of our outputs (by txid:vout).

-3

A wallet examines a transaction for relevance by checking if any of the outputs or inputs are related to its own addresses or scripts. To do this, it needs to know the output scripts (or scriptPubKeys) and the corresponding private keys or scripts that can unlock them. Output descriptors1 are a way of encoding this information in a human-readable string that can be imported or exported by wallets.

Not the answer you're looking for? Browse other questions tagged or ask your own question.