R1 and R2: the settlement that costs a crowd now says so, and no k travels alone - #6
Open
thiagorochatr wants to merge 3 commits into
Open
R1 and R2: the settlement that costs a crowd now says so, and no k travels alone#6thiagorochatr wants to merge 3 commits into
thiagorochatr wants to merge 3 commits into
Conversation
… alone The two recommendations from the review on solanabr#5. R1 — a batch that settles below the pool's floor was silent. The solvency-vs-anonymity trade stays; what changes is that it is now asked for and recorded. - `SettleEpoch` carries `allow_below_floor`, and without it an under-floor batch is refused with its own code (26) rather than settled. Consent, not a bypass: the timeout still governs, and a batch that has not waited it out is still refused with 21. Two codes so a rejection says which gate closed. - A settlement that lands below the floor logs the count it carried, the floor it missed and the timeout it settled on. First log line in this program, and it costs nothing on the crowd path. - The timeout is per pool, in the four bytes `state.rs` had reserved. Zero means the program's default, so the live pool and its unspent notes keep working and POOL_VERSION does not move — bumping it would make `Pool::load` refuse every deployed account. - `mirror settle` requires `--allow-below-floor` instead of warning and settling anyway; `mirror init-pool` takes `--settle-timeout`. R2 — an effective-k can no longer be printed without its bracket. - `Quotation` in mirror-provenance holds the point estimate and the bracket together and is the only thing that renders either. `Anonymity` has no Display, and the type cannot be built without a `Bracket`. - `mirror analyze` refuses outright when the resolved members cannot be bracketed, rather than printing a point estimate with nothing to say how much of it is the pool and how much the tracer's budget. - `PUBLISHED_HEADLINE` puts the measured discount beside every nominal k the tool prints. Its numbers are recomputed from the committed sample by a test rather than typed in. - `tests/no_bare_effective_k.rs` fails if any module formats one of those figures for output by hand. Verified to fail by injecting a violation. O2 — every published signature now carries its finalized slot, read back from the cluster, and both evidence generators say what to do when devnet has pruned the transaction. O3 — PROOF cites `vk_drift.rs`, which already made the check the review asked for; nothing pointed at it. The extra instruction byte moved the pinned wire sizes by one (1228 -> 1229, 1140 -> 1141, 1194 -> 1195). No member ceiling moved: a spend costs three account keys, so one byte was never going to buy or lose a member. 275 tests, `make verify` green.
The program at 8H3cYoiAA9LM36cyPr4UEv38dhHasSu2XPSdiBfyrLEa now carries the
change above, so the evidence had to be taken again rather than kept.
- docs/PROOF.md: a fresh pool at denomination 20000029, five spends settled
in one transaction with two of them pool-signed, the memo callee naming the
vault as signer, a real stake delegation, the vault closing on its floor to
the lamport, and the same four rejections with the same codes. Every row now
carries its finalized slot.
- docs/CROWD.md: six members, six distinct validators, one transaction. It
weighs 1195 bytes — which is the figure the offline encoder predicted after
the flag was added, measured again on the cluster.
- docs/USAGE.md: the member walkthrough re-run at denomination 31000003, so
the blocks that gained a line are captured output rather than edited output.
The nominal-vs-effective note is hand-wrapped to about 78 columns. It sits in
terminal output beside other lines, and a paragraph that wraps raggedly is a
paragraph people scroll past.
data/crowd-result-43000007.json is kept. It is the record behind a published
run, and a superseded measurement is not a deleted one.
…er member The published figures were 2218 and 332 bytes, taken before settle_epoch grew the below-floor flag. Remeasured: 2219 and 333. The +1 is the flag byte, and the 20-member ceiling is unmoved — locks bind there, not bytes. The first attempt at this capture was wrong and is worth recording. The script paid each member's own relay, so a member locked two distinct accounts instead of three, and the batch settled 22 in 1713 bytes. Those numbers are real and they describe a shape nobody uses: paying the relay hands the payout to the one party who already knows which spend was yours. USAGE.md now states the three- accounts-per-member arithmetic that puts the ceiling at 20, so the next reader does not have to rediscover it. README's transaction facts are re-read from the cluster rather than carried over: 35,941 CU, one required signature, 2 static keys and 62 through the table.
Contributor
Author
|
@kauenet — this is the follow-up to your review. R1 and R2 are both in, and O2 and O3 came along with them. I could not set you as a reviewer from here: my account has read-only access to this repository and the Reviewers field needs push, so a mention is the closest I can get. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The two recommendations from @kauenet's review on #5, and the two optional items
that turned out to be cheap.
make verifygreen, 275 tests.R1 — the below-
k_floortimeout settlement is explicit and opt-inThe solvency-vs-anonymity trade stays as it was argued. What changes is that it
can no longer happen quietly.
It has to be asked for.
SettleEpochcarries anallow_below_floorflag.Without it an under-floor batch is refused with its own code —
BelowFloorNotPermitted(26) — rather than settled. The flag is consent, not abypass: the timeout still governs, and a batch that has not waited it out is
still refused with
CrowdTooSmall(21). Two codes so a rejection says which ofthe two gates closed, and a test pins both.
It leaves a mark. A settlement that lands below the floor logs the count it
carried, the floor it missed and the timeout it settled on:
Before this, a solo timeout settlement and a full crowd were the same transaction
shape read two ways — an observer could count accounts, but the floor it fell
short of was not in the transaction at all. It is a log rather than return data
because settlement makes CPIs and each one clears the return-data slot; it is the
program's first log line, and it costs nothing on the crowd path.
The timeout is per pool. Set at
init_poolbesidek_floor, immutableafterwards for the same reason, bounded to between a minute and seven days. It
lives in the four bytes
state.rshad reserved, and zero means the program'sdefault — so
POOL_VERSIONdoes not move and the pools already deployed, withnotes still unspent in them, keep the behaviour they were created with. Bumping
the version would have made
Pool::loadrefuse every live account.mirror settlerequires--allow-below-floorand stops with an explanationrather than warning and settling anyway.
mirror init-pooltakes--settle-timeout.Neither half closes the hole, and
docs/THREAT_MODEL.mdsays so: an adversarialsettler will pass the flag, and the mark reports on your anonymity after the
fact. What they buy is that the trade is now deliberate in the tooling and
visible in the ledger, rather than a default that happens to whoever waited
longest.
R2 — no effective-k without its bracket
Quotationholds the point estimate and the bracket together and is the onlything that renders either.
Anonymityhas noDisplay, and aQuotationcannotbe constructed without a
Bracket, so every figure carries its range on the sameline:
mirror analyzenow refuses outright when the resolved members cannot bebracketed, instead of printing a point estimate with nothing to say how much of
it is the pool and how much is the tracer's budget.
Wherever a nominal
kis surfaced, the measured discount travels with it.mirror treeand every settlement print it. The figures come fromPUBLISHED_HEADLINE, and they are not typed in: a test recomputes ρ, the bracketand the member counts from
data/sample-privacycash-run6.jsonand fails ondrift, so the sample stays the only place the number lives.
The rule is enforced rather than remembered.
tests/no_bare_effective_k.rsfails if any module formats one of those figures for output by hand. It was
verified to fail by injecting a violation before being relied on.
O2 and O3
O2 — every published signature now carries its finalized slot, read back from
the cluster, and both evidence generators explain the pruning fallback. The slot
went into the generators rather than the
.mdfiles, which are overwritten byeach run.
O3 —
docs/PROOF.mdnow citesprograms/mirror-pool/tests/vk_drift.rs. Thattest already did what the review asked for: it regenerates the key from the
committed seed under the committed
Cargo.lockand compares it to the deployedvk.rselement by element. Nothing pointed a reader at it.The evidence was retaken, not kept
The devnet program at
8H3cYoiAA9LM36cyPr4UEv38dhHasSu2XPSdiBfyrLEawas upgradedto this code, so every published capture was produced again against it:
docs/PROOF.md(a fresh pool, five spends settled together with two of thempool-signed, a real stake delegation, the vault closing on its floor to the
lamport, the same four rejections with the same codes),
docs/CROWD.md(sixmembers, six distinct validators, one transaction) and the
docs/USAGE.mdwalkthrough.
One byte of instruction data moved the wire sizes and nothing else. 1228 →
1229, 1140 → 1141, 1194 → 1195, 2218 → 2219, 332 → 333. No member ceiling moved:
a spend costs three 32-byte account keys, so a byte was never going to buy or
lose a member. Both numbers are pinned separately for exactly this reason — the
size moving alone means the encoding changed, and the ceiling moving means the
crowd did.
One correction worth stating. The first attempt at reproducing the
lookup-table settlement paid each member's own relay, which makes a member cost
two distinct account locks instead of three, and the batch settled 22 in 1713
bytes. Those numbers are real and they describe a shape nobody should use —
paying the relay hands the payout to the one party who already knows which spend
was yours. Remeasured at three accounts per member it is 20 members, 2219 bytes
legacy, 333 through the table, which is the published claim.
docs/USAGE.mdnowstates the arithmetic that puts the ceiling at 20, so the next reader does not
have to rediscover it.
Thank you for the review — R1 and R2 were both sharper than the code that
prompted them.