# The top tier prover can not re-prove

Taiko's LibProving.proveBlock asserts contestBond==0 but default is 1, so top-tier prover re-proving a different transition always reverts.

- Payout: Contest reward
- Severity: medium
- Program: Taiko
- Credited: Shield
- Disclosed: 2024-04-26
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2024-03-taiko-findings/issues/305
- Library page: https://bugbountylibrary.com/r/c4%3A2024-03-taiko%3AM-02
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:solidity technique:incomplete-fix technique:source-review vuln:business-logic

**Target:** LibProving.proveBlock in Taiko L1 protocol contracts
**Root cause:** The top-tier re-prove branch asserts ts.contestBond == 0, but transition storage initializes contestBond to 1 for gas savings, so the assert always fails for a fresh transition.
**Steps:**
1. Call `proveBlock` with `LibTiers.TIER_GUARDIAN` for a block, creating a transition with `ts.contestBond = 1`.
2. Call `proveBlock` again as top-tier prover with a different blockHash/stateRoot for the same block.
3. Observe the `assert(ts.contestBond == 0 && ...)` in LibProving.sol#L219-L236 reverts, blocking re-proving.
4. Change assert to `ts.contestBond == 1` and rerun test `test_L1_GuardianProverCanOverwriteIfNotSameProof_test` to confirm success.
**How found:** Code reading of the top-tier re-prove branch; noticed the assert compared contestBond to 0 while the transition initialization sets contestBond = 1 to save gas, then wrote a Foundry PoC to confirm the revert.
**Insight:** When auditing assert/require checks against struct fields, cross-check the field's initialization default — sentinel values like 1 (used for gas savings) silently break equality-to-zero guards.
