Skip to content

Limonata v0.3.6 - encrypted-mempool concentration guard (MANDATORY coordinated upgrade at height 1,650,000)

Latest

Choose a tag to compare

Limonata v0.3.6 - encrypted-mempool concentration guard

MANDATORY coordinated upgrade at height 1,650,000. Every validator must be running v0.3.6 by that
height or it will stop producing blocks. This is a consensus-breaking change gated by an on-chain
governance proposal; do not upgrade early and do not upgrade late.

Built from commit effa377d.

What changes

The encrypted mempool's committee concentration guard becomes two-clause, behind a new parameter so
that replaying history stays byte-identical.

  • Confidentiality clause. The threshold becomes t = floor(2S/3) + n, so no coalition holding two
    thirds or less of committee stake can ever reach it. The previous single-clause form
    (t = floor(2S/3) + 1) did not have that property once points were weighted by stake.
  • Strand clause. The guard fails closed if any single operator holds S - t + 1 points or more,
    which is the point at which that operator alone could withhold its share and prevent decryption.
  • One-way ratchet. Once the gate flags are on, UpdateParams cannot turn them back off.

The practical effect is that the encrypted mempool becomes usable. The single-clause guard is closed
against realistic committees - not by accident but structurally - which is why encrypted submission
does not currently work on the live testnet. The two-clause form opens it to a committee that is
actually decentralized, and keeps it closed to one that is not.

Replay safety

Chains that have no record of the new parameter behave exactly as before: the legacy threshold, no
strand clause, byte-for-byte identical results. The flag is flipped by the upgrade handler
encmempool-strict-concentration-v1, and DefaultParams() has it on so new chains are born correct.

One subtlety is worth stating because it cost us a rehearsal to find. An earlier build read the new
parameter through a metered store read. The returned value was replay-inert, but the gas was not:
any historically rejected SubmitEncrypted transaction would have recorded a different gas_used,
diverging LastResultsHash and breaking sync-from-genesis. Static analysis and fuzzing both passed;
only a real devnet upgrade followed by a full resync caught it. The shipped build threads the flag in
from callers that already hold the loaded parameters, and the ratchet reads through a throwaway
infinite gas meter. Replay-inert return values are not the same thing as replay-inert gas.

Verifying this release

curl -sfLO https://github.com/Limonata-Blockchain/limonata/releases/download/limonata-v0.3.6/limonatad-linux-amd64.tar.gz
curl -sfLO https://github.com/Limonata-Blockchain/limonata/releases/download/limonata-v0.3.6/SHA256SUMS.txt
curl -sfLO https://github.com/Limonata-Blockchain/limonata/releases/download/limonata-v0.3.6/SHA256SUMS.txt.asc
curl -sfLO https://github.com/Limonata-Blockchain/limonata/releases/download/limonata-v0.3.6/limonata-release-signing-key.asc

gpg --import limonata-release-signing-key.asc
gpg --verify SHA256SUMS.txt.asc SHA256SUMS.txt
sha256sum -c --ignore-missing SHA256SUMS.txt

tar xzf limonatad-linux-amd64.tar.gz
./limonatad version --long | head -3      # expect version v0.3.6, commit effa377d

The signing key is A45380198F390AF69126AE12E4ECEC477C1735FB
(Limonata Foundation, release signing).

This archive is larger than v0.3.5's because the binary keeps its debug symbols, which makes a stack
trace readable if a validator does halt. Behaviour is unaffected.

Upgrading

With cosmovisor, the upgrade info in the governance plan points at this archive and the swap is
automatic. Manually: let the node halt at 1,650,000, replace the binary, restart.

Also in this governance proposal

The same proposal recovers the expired IBC light client 07-tendermint-0, which restores transfer
channel-0 to Osmosis. That action is unrelated to the mempool change and executes when the proposal
passes, not at the upgrade height. Both messages apply atomically - governance applies both or
neither.