Report a disagreement
A disagreement between two implementations is the most valuable bug report this project can receive. It means someone's artifacts mean two different things.
- The six ordinary causes to rule out before you write anything up, starting with two indexers sitting at different heights.
- The seven things to collect, and why the reduced vector is worth more than the other six together.
- Where the report goes, and why a state disagreement starts at the protocol repository rather than the indexer one.
- What a gap in the baseline changes, including
spec_sha256. - What to do with affected artifacts while the question is still open, and what never to do to your own code in the meantime.
First, rule out the boring causes
Six checks, all of them cheap, and any one of them can end the question before it starts. Begin with the first row: one indexer is further behind than the other, and being behind is not being wrong.
| Cause | How to check |
|---|---|
| Different heights | Compare indexed_height from both. An indexer that is behind is not wrong. |
| Different networks | Compare network. |
| Different specs | Compare spec_sha256. Different specs are allowed to differ. |
| One is mid replay | Check /ready. During a reorg replay an indexer should refuse traffic, not serve half state. |
| A reorg between the two calls | Repeat both calls and see whether the difference is stable. |
| A known deviation | Read docs/deviations.md in this repo. A recorded deviation is a known difference, not a new one. |
If all six are clear and the state still differs, it is a real disagreement.
What to collect
Seven items, in the order that narrows the search. The first three locate the disagreement, the next three record what happened at that height and which rule you think it breaks, and the last one turns the whole thing into a test somebody can run.
- Both status responses. Full JSON from
GET /patina/statuson each side. - The first differing height. Bisect until you have the single block where the state roots diverge.
- Both state roots at that height, and both at the height before it.
- The raw block. Its hash, and the raw hex of the transaction that seems responsible.
- Both interpretations. What each implementation did with that transaction, in plain words: created an artifact, chose a successor, recorded a reason code.
- The baseline rule you think applies, quoted, with the section it comes from.
- A reduced vector. The smallest scenario that reproduces the difference.
A vector turns an argument into a test. Everything else is context. If you can only produce one artefact from your investigation, produce the vector.
Report template
Copy this as it stands and fill in every line. Leave a field blank rather than deleting it, because a blank line says you could not determine that value, and a missing line says nothing at all.
Summary
One sentence: what differs, at what height, on what network.
Implementations
A: name, indexer_version, parser_version, spec_sha256
B: name, indexer_version, parser_version, spec_sha256
Divergence
network:
first differing height:
block hash:
state root A:
state root B:
state root at height - 1 (both, to show they agreed before):
Transaction
txid:
raw hex:
which output carries the marker:
marker bytes:
Interpretations
A did:
B did:
Baseline rule
quoted text, and which section it is from
Reduced vector
attached scenario file, or inline
Impact
how many artifacts are affected, and whether any are founding
Where to send it
Open an issue on the protocol repository bitcoinuniverse/patina. Indexer specific bugs
belong on bitcoinuniverse/index-patina, but a state disagreement always goes to the protocol
repository first, because the question is what the rule says before it is whose code is wrong.
Report it in public. A disagreement fixed in private leaves everyone else running whichever behaviour they happened to implement. Publishing it is the same commitment the project makes about everything else it knows, which is written out on Transparency.
How it gets resolved
-
Reproduce
The reduced vector is run against both implementations and the difference is confirmed.
-
Decide what the baseline requires
The rule is either already clear, in which case one implementation has a bug, or it is ambiguous, in which case the baseline has a gap.
-
Write it down
A bug becomes a fix. A gap becomes a change to the baseline, which changes
spec_sha256and goes through the upgrade boundary. -
Add the vector permanently
The reduced case joins the golden vectors so the same disagreement cannot come back.
-
Publish the outcome
Including which artifacts were affected and how their state changed once both sides agreed.
While it is unresolved
- Say so publicly. An unresolved disagreement is a fact about the system, not an embarrassment to manage.
- Do not quietly switch behaviour to match the other side. That destroys the evidence and can turn one bug into two.
- Do not present affected artifacts as settled. Show that their state is disputed and at what height.
- Keep serving. An indexer with a known, published disagreement is more useful than one that hides it.