> ## Documentation Index
> Fetch the complete documentation index at: https://docs.parallaxprotocol.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Confirmations and risk

> How many confirmations to wait for on Parallax, how the network status page works them out from live mining data, and when to hold or pause deposits.

The risk an exchange takes on a deposit is that it is **reversed**: the
deposit's block is replaced by a competing chain, after the coins have been
credited and withdrawn as something else. Confirmations are the defence.
How many are enough depends on one thing above all: **how much of the
mining power the largest miner controls**. That changes over time, so on
Parallax the right number is something you measure, not a constant you set
once.

The [network status page](https://status.parallaxprotocol.org) measures it
continuously and publishes the result, with the evidence behind it, as
JSON. This page explains the method and how to turn it into a deposit
policy. The [Network status API](./status-api) page is the reference for
reading the data, and ends with the policy below written as code.

<Warning>
  Parallax is a young network, and its hashrate has at times been
  concentrated in a single pool, including periods when one pool found most
  of the blocks. While that is so, no number of confirmations is safe in the
  usual sense (see [Half the hashrate or more](#half-the-hashrate-or-more)).
  Check the live **Decentralization** and **Recommended confirmations** tiles
  before you set your policy, and build it so it reacts when they change.
</Warning>

## The threat

To reverse a payment, a miner builds a competing chain in secret, one that
leaves the payment out. Once that chain is longer than the public one, the
miner publishes it. Nodes always follow the chain with the most work, so
they switch to it, and the payment is gone, along with every confirmation
it had. Each confirmation is one more block the secret chain must overtake.

A pool counts as **one** miner, because it decides what all its miners
work on. What matters is the share of blocks found by the largest pool,
not the number of individual miners.

## How the wait is worked out

The status page works out the wait against the largest miner of the last 7
days, from its share of those 7 days' blocks.

### Below half the hashrate

A miner with less than half the hashrate falls behind on average, so it
can only catch up by luck, and its odds shrink with every confirmation. The
status page works them out exactly, as in
[Rosenfeld (2014)](https://arxiv.org/abs/1402.2009), not with the
approximation in section 11 of the [Bitcoin paper](https://bitcoin.org/bitcoin.pdf),
which understates them: against 30% of the hashrate, 99.9% safety takes 32
blocks, not the paper's 24.

Those odds assume the miner was mining in secret the whole time the payment
was being confirmed, which gives it a head start. But hashrate cannot be in
two places at once. If the miner's blocks keep arriving on the public chain
at the rate its share says they should, it was not mining in secret. It
could only start after the payment is accepted, from as far behind as the
payment is deep, and that needs far fewer confirmations to defend against.
It could still hide part of its hashrate and pass the gap off as bad luck,
up to about a quarter of it, so the shorter waits allow for that. They hold
for deposits credited while the miner is seen **mining in the open** (see
[Hidden mining](#hidden-mining)).

Confirmations needed against the largest miner's share, worked out with the
status page's own code:

| Largest miner's share | 99% | 99.9% | 99.99% | 99.9%, miner seen mining in the open |
| - | - | - | - | - |
| 10% | 4 | 6 | 8 | 6 |
| 20% | 8 | 13 | 18 | 13 |
| 25% | 12 | 20 | 27 | 15 |
| 30% | 20 | 32 | 44 | 19 |
| 35% | 36 | 58 | 81 | 25 |
| 40% | 82 | 133 | 186 | 32 |
| 45% | 331 | 539 | 754 | 51 |
| 49% | over 1,000 | over 1,000 | over 1,000 | 205 |

At 10 minutes a block, 6 confirmations is about an hour, 32 about 5 hours,
and 133 about a day. Below a 25% share the two columns agree, because the
open-mining check only watches a miner with 25% of the blocks or more.

### Half the hashrate or more

A miner with a majority finds blocks faster than everyone else together, so
it always catches up eventually, however long the wait. Watching it does
not help either: it can start a secret chain after the payment is accepted,
beginning below it.

What protects a payment then is **cost**. The blocks the miner replaces are
mostly its own, and their rewards are lost with them: about its share of
each block's pay, for every confirmation. Wait until reversing the deposit
would cost the miner more than the deposit is worth:

```
confirmations ≥ deposit value ÷ (miner's share × value of one block's pay)
```

This leaves out what cannot be counted, such as the pool's miners leaving
it, or the price falling once an attack is seen, which cut both ways. It is
the weakest protection on this page. While a majority exists, also cap how
much you accept (see [Building a policy](#building-a-policy)).

### Not counted

Neither method sees hashrate that is rented or brought in from elsewhere
for an attack, because it never shows on the chain beforehand, nor pools
that work together. Large deposits deserve a margin above what the status
page says.

As a rough guide to rented hashrate: matching the whole network's hashrate
costs about what miners earn, which the status page reports as
`securityBudget.laxPerDay`. Divided by 144, that is roughly what an
attacker pays per block it mines. A deposit worth more than your
confirmation count times that figure is worth renting hashrate to attack,
and should wait longer or be reviewed by hand.

Majority attacks are not only theory. Ethereum Classic lost about 219,500
ETC to repeated reorganizations in January 2019, and attackers double-spent
about 388,000 BTG at exchanges on Bitcoin Gold in May 2018. In both cases
it was exchanges crediting deposits that lost the funds.

## Hidden mining

Hashrate spent on a secret chain is missing from the public one. So a miner
mining in secret stops publishing blocks, or publishes fewer than its share
says it should. The status page watches the largest miner's last 144
blocks, once it has 25% of the blocks or more, and asks: how likely is it
that a miner mining openly, at this share, would publish this few blocks in
this long? The answer sets a status dot and the `confirmations.watch`
object in the API.

| Dot | `watch` | Chance for a miner mining openly | Meaning |
| - | - | - | - |
| Green: mining in the open | `open: true` | 1 in 100 or better | Its blocks arrive as its share says. The shorter waits apply |
| Grey: unusually quiet | `open: false`, `level: null` | Worse than 1 in 100 | Back to the longer waits |
| Amber: possibly mining in secret | `level: "warn"` | Worse than 1 in 10,000 | An alert is raised |
| Red: hold payments | `level: "critical"` | Worse than 1 in a million | Payments in blocks after `fromHeight` may be reversed |

How quickly the dot changes depends on the share. At 60% of the blocks it
turns amber after about 2.6 hours without one of the miner's blocks and red
after about 3.8 hours. At 94% it takes about 1 hour 20 minutes and 2 hours.

### What a quiet miner does and does not mean

**A hidden-mining signal is not, by itself, an attack.** A pool that is
offline looks exactly the same: hashrate spent on nothing is as absent from
the public chain as hashrate spent on a secret chain. Pools go down for
maintenance, lose their node, have network trouble, or have miners move
elsewhere for a while. And at 1 in 100, the grey dot shows up by chance
from time to time even when nothing at all is wrong. A quiet stretch that
ends with the miner simply resuming, and no block replaced, was not an
attack.

What the signal tells you is **where a reversal would come from, and which
blocks it could reach**: those after `watch.fromHeight`. That makes the
right response narrow. Hold the deposits it could affect, and let the rest
of the data decide whether anything happened:

<Steps>
  <Step title="Hold only what is exposed">
    While `watch.level` is `"critical"`, hold deposits in blocks above
    `watch.fromHeight`. Deposits in earlier blocks are not exposed by this
    stretch and follow your normal rules. At `"warn"`, stop using the shorter
    open-mining waits and hold large deposits.
  </Step>

  <Step title="Wait for the miner to come back">
    The quiet stretch ends when the miner's blocks appear again. Either they
    extend the public chain, or they replace part of it.
  </Step>

  <Step title="Check whether anything was replaced">
    Look at `staleBlocks.lastReorg` and `staleBlocks.reorgEvents` on the
    status page, and at your own scanner's reorganization log. If there is
    **no reorganization reaching down to `fromHeight` or below**, the blocks
    after `fromHeight` stood: the miner was offline or unlucky, not mining a
    secret chain. Release the held deposits; they have their full count of
    confirmations. If a reorganization did reach that far, the blocks were
    replaced: rescan, and treat it as an incident.
  </Step>

  <Step title="Look for corroboration while you wait">
    The other figures help tell an outage from an attack before it resolves.
    A pool that is visibly down (its own website or dashboard, which the
    status page links from `decentralization.topMiners[].website`, or an
    announcement) points to an outage. So does a `propagation` or
    `slow-miner` alert, which points to network trouble rather than
    deliberate withholding. Unexplained silence from a pool that otherwise
    looks healthy, in a period where a large deposit is pending, is the
    case that deserves the most caution.
  </Step>
</Steps>

The incident history helps calibrate this. The status page records every
quiet stretch as a `withholding` incident, kept for 90 days. Comparing
those incidents with `staleBlocks.reorgEvents` over the same periods shows
how often a quiet miner has been followed by a reorganization on Parallax,
and how long its quiet stretches usually last. That record, together with your own
reorganization log, is what lets you hold briefly and precisely instead of
pausing all deposits whenever a pool hiccups.

## Building a policy

A workable policy has four parts.

**1. A required count per deposit, from live data.** Choose a confidence by
deposit size, for example 99.9% for ordinary deposits and 99.99% for large
ones, and read the count from `confirmations.levels`, or from
`openLevels` when `watch.open` is `true` at the moment you credit. While
`majority` is `true`, use the cost formula instead, with a safety margin.
Never go below a floor of your choosing.

**2. Exposure limits.** Cap the value credited per deposit, per account and
per hour, lower while `decentralization.grade` is `concentrated` or
`critical`. While a majority exists, the cap is what actually bounds your
loss.

**3. Halt conditions.** A short list of signals that hold or pause
deposits, below. The fields they name are described in
[Fields for a deposit policy](./status-api#fields-for-a-deposit-policy).

**4. Withdrawals stay open.** These risks are to deposits. A reorganization
can also drop a withdrawal you sent, but that is recovered by rebroadcasting
the same signed transaction (see [Withdrawals](./withdrawals#after-broadcast)).

### Halt conditions

| Signal | Source | Response |
| - | - | - |
| Your node is not synced, has few peers, or its head is over 2 hours old | Your node | Stop crediting from that node |
| Your nodes disagree on the block at a height a few blocks below the head, or disagree with `bestBlock` | Your nodes, status page | Pause all crediting until they agree |
| `split` alert | Status page | Pause all crediting |
| `reorg` alert, `warn` (depth 3 to 5) | Status page, your scanner | Pause; check whether any pending deposit was in the replaced blocks; resume when clear |
| `reorg` alert, `critical` (depth 6 or more) | Status page, your scanner | Pause all crediting; treat as an incident |
| `watch.level` is `"warn"` | Status page | Stop using `openLevels`; hold large deposits |
| `watch.level` is `"critical"` | Status page | Hold deposits in blocks above `watch.fromHeight` until the miner returns, then [check for reorganizations](#what-a-quiet-miner-does-and-does-not-mean) |
| No block for over 2 hours (`serverTime − bestBlock.timestamp`) | Status page, your nodes | Hold new credits; usually goes with a quiet large miner, so check `watch` |
| `majority` is `true` | Status page, your node | Switch to cost-based counts and lower caps, or suspend deposits, by your risk appetite |
| `confirmations.judged` is `false`, or `levels` give `null` without a majority | Status page | Manual review for anything above your floor |
| Status page unreachable | | Use [your own largest-share figure](./status-api#what-the-status-page-can-and-cannot-tell-you) and the table above; keep your node checks |

[A policy in code](./status-api#a-policy-in-code) puts these rules together
in Python.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.