In PBFT, the pre-prepare phase lets the primary assign a sequence number to a request, the prepare phase makes the replicas agree on that order within the current view, and the commit phase makes sure the order will survive view changes before the request is executed.
Assume \(n = 3f + 1\) replicas, at most \(f\) faulty, current view \(v\).
| Point | Pre-prepare | Prepare | Commit |
|---|---|---|---|
| Who sends | Only the primary | Every backup that accepts the pre-prepare | Every replica that is "prepared" |
| Message | <PRE-PREPARE, v, n, d> + request m | <PREPARE, v, n, d, i> | <COMMIT, v, n, d, i> |
| Purpose | Propose an order: assign sequence number \(n\) to request with digest \(d\) | Agree on the order inside the view; ensures no two different requests get the same \(n\) in view \(v\) | Agree that enough replicas are prepared, so the order is final even if the view changes |
| Acceptance condition | Backup accepts if signature, view and digest are valid, \(n\) is within watermarks, and it has not accepted another request for the same \(v, n\) | Replica is prepared after the pre-prepare plus \(2f\) matching prepares from different replicas | Replica is committed-local after \(2f + 1\) matching commits (including its own) |
| Outcome | Request ordered by primary | Order guaranteed within the view | Request executed and reply sent to the client |
Why three phases? A faulty primary could send different orders to different replicas; the prepare phase detects this, since \(2f + 1\) matching messages (pre-prepare plus \(2f\) prepares) cannot be gathered for two conflicting requests. The commit phase is needed because a replica being prepared alone does not mean others know it; after \(2f + 1\) commits, any future view will include at least one honest replica that knows the order, so it is never changed.
Finally, the client accepts the result after \(f + 1\) matching replies.