PATINA docs

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.

What you will know after this page
  • 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.

Check these before writing anything up.
CauseHow to check
Different heightsCompare indexed_height from both. An indexer that is behind is not wrong.
Different networksCompare network.
Different specsCompare spec_sha256. Different specs are allowed to differ.
One is mid replayCheck /ready. During a reorg replay an indexer should refuse traffic, not serve half state.
A reorg between the two callsRepeat both calls and see whether the difference is stable.
A known deviationRead 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.

  1. Both status responses. Full JSON from GET /patina/status on each side.
  2. The first differing height. Bisect until you have the single block where the state roots diverge.
  3. Both state roots at that height, and both at the height before it.
  4. The raw block. Its hash, and the raw hex of the transaction that seems responsible.
  5. Both interpretations. What each implementation did with that transaction, in plain words: created an artifact, chose a successor, recorded a reason code.
  6. The baseline rule you think applies, quoted, with the section it comes from.
  7. A reduced vector. The smallest scenario that reproduces the difference.
The reduced vector is the important part

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

  1. Reproduce

    The reduced vector is run against both implementations and the difference is confirmed.

  2. 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.

  3. Write it down

    A bug becomes a fix. A gap becomes a change to the baseline, which changes spec_sha256 and goes through the upgrade boundary.

  4. Add the vector permanently

    The reduced case joins the golden vectors so the same disagreement cannot come back.

  5. 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.