Skip to content

Learn

Crypto Spot Research

Compact block filters: a match is a candidate, not a payment

A compact block filter is a screening device. A match tells a researcher which block deserves inspection; it does not identify a payment, recipient amount or beneficial owner. Research that turns filter hits directly into adoption or transfer totals skips the evidence needed to establish those quantities.

The useful deliverable is a candidate ledger connecting filters to verified block contents. It should also explain why non-matching blocks were excluded, which scripts were queried and how the filters themselves were checked. Screening accuracy and economic interpretation are separate stages.

Define the searchable object correctly

BIP 158, under Block Filters and Contents, specifies the basic filter’s elements: relevant output scripts and previous-output scripts for ordinary inputs, with stated exclusions including OP_RETURN outputs. It is not a general index of arbitrary address text or every byte appearing inside a transaction.

Build a frozen target-script set from the actual research scope. Store each script’s bytes and the rule that placed it in the set. An address copied from an interface must be converted into the correct script for its network and type before it becomes a query element. A label such as treasury is not itself an element.

Keep derivation coverage explicit. If the study monitors scripts associated with indices zero through ninety-nine, the filter process cannot discover index one hundred merely because it has no false negatives for the elements it actually checks. A correct search over an incomplete target set remains an incomplete wallet study.

Separate filter construction from filter provenance

The BIP’s Golomb-coded-set description permits false matches for elements outside the set. Its basic parameters include M = 784931. For the stated construction, the per-absent-element false-match probability is 1/M; that parameter is not the fraction of all positive block candidates that will be irrelevant.

BIP 157’s Abstract and Motivation describe retrieving complete blocks after matches and checking filter-header histories, with an honest-peer assumption in the protocol’s assurance. A filter header chain is not automatically a consensus commitment in an ordinary Bitcoin block header. Preserve the evidence for selecting the correct filters rather than attaching the word verified to one server’s unchecked response.

Save block hash, filter type, raw filter bytes, filter hash, available filter-header references and peer observations. If peers disagree, retain the conflict and investigate the affected block. A matching filter from an untrusted source can create extra work; a falsified non-match can be more serious because it might hide a relevant block.

A hypothetical eight-candidate review

Assume a fictional research run examines one thousand selected-chain blocks against a declared wallet-script set. It produces eight positive block candidates. The full blocks are obtained and checked, with no retrieval failures in this invented example. Three contain an exact queried script in a field covered by the filter; five contain none.

StageCountWhat it means
Blocks screened1000Defined block population queried
Positive candidates8Blocks requiring detailed inspection
Exact script matches after inspection3Relevant block contents confirmed
False candidates5Screening matches without an exact target element
Non-matching blocks992Excluded by the filter, not independently audited here

Candidate precision in this run is 3/8 = 37.5%. The false-candidate share among positives is 5/8 = 62.5%. Neither fraction estimates the population false-positive rate, whose denominator is truly absent tests. The example has not independently established the truth status of every negative test, nor defined how many absent script queries occurred across the target set.

Do not publish 5/1000 as a measured implementation false-positive rate either. That divides observed false block candidates by screened blocks, mixing block-level screening and element-level membership. It can describe the run’s extra-block workload if labeled precisely, but it is not the BIP’s 1/M quantity.

The numbers are deliberately hypothetical. They are not observed performance of a wallet, peer or filtering library, and the eight-candidate outcome should not be used to reverse-engineer a new filter parameter.

A true script match is still not a payment count

Inspect the three confirmed blocks in the example. Suppose one creates an output of 0.4 BTC to a target script, another creates 0.6 BTC, and the third spends the first output. All three can be relevant to the script set, but only two are the stipulated incoming outputs.

The gross incoming amount is 0.4 + 0.6 = 1 BTC under the defined receipt rule. It is not three payments and certainly not three bitcoin because there were three relevant blocks. Current balance requires following spent status and any other relevant outputs separately.

Record transaction identifier, output index for creation events, consumed outpoint for spend events, value and script relationship. If several targets match one block, inspect the block once while preserving every matching target. Repeating the block for each target and adding whole-block totals would multiply unrelated activity.

Ownership attribution remains another question. Exact script bytes establish the technical match; the official address statement or other attribution evidence establishes why the script belongs in a named entity’s study. Do not let a probabilistic screening method become an identity inference.

Why more targets change screening workload

One absent element and a wallet containing many candidate scripts are different query designs. With q absent elements, a union bound on at least one false match is at most min(1, q/M), provided the individual construction probabilities apply. This bound does not require treating the queries as independent and is not an exact expected outcome for a particular block.

For a purely illustrative q = 1000, q/784931 is about 0.001274, or 0.1274%. The single-element probability is about 0.0001274%. The different decimal positions matter: substituting a wallet-wide rate for a single-element rate can greatly misstate the amount of extra block inspection required.

Keep q and duplicate-script handling in the run record. A larger derivation range may recover relevant activity while also increasing screening candidates. That is a coverage and workload change, not automatic evidence that the data source deteriorated.

Different failure mechanisms need different responses

If a filter matches but the full block cannot be retrieved, label the candidate unresolved. It is not yet a false match. If a block is retrieved but its hash does not match the selected header, fix the identity problem before inspecting its scripts.

If the research question searches OP_RETURN payload text, the basic filter’s exclusions make it unsuitable as a completeness certificate for that task. This is a coverage mismatch, not a random false negative under an otherwise applicable membership test.

If the target set omitted a changed address branch, expanding the script set and rerunning the same block window is appropriate. Preserve the earlier set and results so that newly found history is not presented as newly occurring economic activity.

Identify candidate blocks by network and block hash rather than height alone. A replacement block at the same height requires its own filter and content checks. Keeping the former branch’s candidate identity prevents a reorganization from silently overwriting which object was inspected.

Keep candidate classifications exhaustive. If only seven of the eight candidate blocks were retrieved, an illustrative reconciliation could be three true, four false and one unresolved. Do not retain the original five-false count or delete the unresolved case before computing precision. A changed candidate set requires checking scripts, branches and filters; a changed classification requires checking retrieved content and interpretation.

A practical release check

CheckRequired recordTreatment of a failure
Target identityExact script bytes and inclusion reasonQuarantine ambiguous targets
Block identityNetwork, selected hashes and rangeResolve branch mismatches
Filter authenticityType, bytes, headers and peer checksPreserve disagreement
Positive verificationFull block and exact matching fieldKeep unavailable blocks unresolved
Economic classificationCreated or spent outpoint and quantityDo not count raw hits as payments
Metric denominatorBlocks, elements, candidates or absent testsRename unsupported accuracy claims

Recheck after a target-set revision, filter-header conflict, parser correction or recovered block. The released note should report screened coverage, verified candidates, unresolved candidates and the explicitly defined economic observations. It can quantify inspection workload without claiming a global wallet completeness or error-rate result the run did not measure.

FAQ

Can a filter match prove that my address received bitcoin?

No. Retrieve and verify the full block, identify the relevant script field and classify the resulting output or spend.

Are five false candidates out of eight a 62.5% false-positive rate?

They are a 62.5% false-candidate share among positives in that hypothetical run. A false-positive rate uses truly absent tests as its denominator.