Repository navigation
TL;DR — why upgrade
1.0.7.9 keeps merged mining alive through Pearl's salted noise-seed hard fork, and fixes two sync problems that were causing reorg churn and nodes silently failing to follow each other.
Pearl activated a consensus change (certificate V3) that alters how the ZK proof's noise seeds are derived. Because merged mining submits the same proof to both chains, every AuxPoW block produced after that fork carries a V3-derived proof — and a node without this release rejects it.
All node operators, pools and wallet users should upgrade. Nodes that stay on 1.0.7.8 will reject post-fork merge-mined blocks and stop following the chain.
1. Pearl V3 salted noise-seed support
Pearl now binds each matrix Merkle root with a keyed BLAKE3 hash under a per-side domain salt that also commits the matrix dimension:
bound_a = blake3(hash_a || m_le32 || 0^28, key = blake3("pearl/cert-v3/noise-seed/A"))
bound_b = blake3(hash_b || n_le32 || 0^28, key = blake3("pearl/cert-v3/noise-seed/B"))
The derivation feeds mining itself, so a verifier without it computes different seeds and rejects otherwise-valid work.
zk-powgains the V3 derivation and certificate version 3, threaded through prove, verify, mine and proof parsing. The derivation is not carried on the wire — the wire always holds raw roots — so it is supplied from the certificate version.- Pinned parity vectors from upstream cover both derivations. These are consensus: if they drift, blocks we mine are rejected by Pearl and vice versa.
py-pearl-mining0.3.0 and the Go FFI bindings gain V3 entry points. Every pre-existing entry point keeps its ABI and stays on the legacy derivation, so nothing that mines MDL natively changes behaviour.
AuxPoW accepts either derivation
The embedded Pearl parent may be pre- or post-fork, and the derivation is not on the wire, so the AuxPoW verifier tries salted first and falls back to legacy. A proof is bound to exactly one derivation, so trying both cannot admit an invalid proof — it costs one extra cached verify on the rejecting branch.
Pools need no change beyond what they already do. modelOS has always required aux pools to normalise the embedded Pearl header's ProofCommitment to the V1 form; since the MoE fork that meant rewriting from version 2. Now it is version 3 — the same one-field rewrite, from a different source value. The real Pearl block sent to pearld keeps its native commitment.
2. Peers are no longer penalised for honest behaviour during forks
The per-peer quality gate struck a peer for every block that did not extend our tip — including valid side-chain blocks and orphans, which are the normal result of two miners finding a block at the same height.
On a chain with a real fork rate that is self-reinforcing: peers hit the strike limit, get gated out of the block-download path, propagation slows, which produces more forks and more strikes.
Inbound peers made it worse by starting at the limit, so an unsolicited connection was gated before doing anything wrong and could not earn its way back. That is why node-to-seed sync worked while node-to-node did not.
- Only genuine consensus failures strike. Valid side-chain blocks and orphans do not. Neither opens a cheap flood: both still cost real proof-of-work, since the ZK proof is verified before orphan handling.
- Inbound peers start at 3 of 5 — still more suspect than outbound, no longer pre-gated.
- Strikes decay one per 10 minutes, so a peer that hit a bad patch recovers instead of staying downgraded for the life of the connection.
- Unrequested-block disconnect, the compact-block rate limit and the parent-known gate are unchanged.
3. Compact-block announcements now feed peer bookkeeping
A cmpctblock is a block announcement, but it was never recorded the way an inv is. The sync manager therefore never learned that a high-bandwidth peer had advanced — the peer's height stayed frozen at the value from the version handshake.
That deadlocks a node which falls behind while connected only to high-bandwidth peers. It needs a sync peer to catch up; sync-peer selection only picks a candidate advertising a greater height; and the message that would have refreshed that height is the inv it no longer receives, because the peer announces via cmpctblock instead.
Seen in production as two nodes permanently connected, one hundreds of blocks behind, neither making progress — getpeerinfo showed syncnode=false on every connection and a startingheight hundreds of blocks stale.
4. Protocol version 2 — acceptance floor deliberately unchanged
wire.ProtocolVersion moves 1 → 2 to mark software that understands the V3 derivation.
MinAcceptableProtocolVersion stays at 1 and is now a standalone constant rather than being derived from ProtocolVersion. The coupling was a hazard: bumping the version would have raised the floor in the same release, so the first node to upgrade would refuse every peer still on the old version — isolating itself, then splitting the network into two mining halves whose reunion is a deep reorg.
The floor will be raised in a later release, once the fork has activated and old nodes genuinely cannot follow the chain. DNS seeders must be rebuilt before that happens, or they are refused at handshake and peer discovery breaks network-wide. A test now fails the build if the two are ever raised together.
Compatibility: peers negotiate min(ours, theirs), and the AuxPoW path accepts both derivations, so an upgraded node accepts every block an old node accepts. The network stays whole while adoption happens.
Who must upgrade
| Component | Required | Why |
|---|---|---|
Node (modelosd) |
yes | verifies ZK proofs; rejects post-fork AuxPoW blocks without this release |
Wallet (oyster) |
yes | the embedded SPV client fully verifies proofs above the last checkpoint, so an un-rebuilt wallet stops following the chain once salted blocks appear |
| DNS seeders | not yet | required before the acceptance floor is raised in a later release |
| Pools | config only | normalise the embedded Pearl commitment from version 3 instead of 2 |
Upgrade
Standard rebuild — no database migration, no reindex, no config change.
git pull && task build:blockchain
Restart the node. Verify with modelosd --version (expect 1.0.7.9).
Tests
- 3 upstream consensus parity vectors for the seed derivation (legacy, salted, salted MoE)
- 7 peer quality-gate properties
- 2 protocol-floor guards, verified failing on the coupled state
- Full
blockchain,wire,peerandnetsyncsuites green under-tags zkpow