Prior to this fix, proposal_vote.rs:486 set the tx TTL to `tip_slot + VALIDITY_RANGE_SLOTS` (the unclamped default) while the new stake output's Voted lock embedded `posix_time = validity_upper_ms` which the MCP layer at tools.rs:3197 may have CLAMPED to `voting_end_slot` to keep the validity range inside the voting window. The TX TTL slot and the slot underlying validity_upper_ms then diverged whenever the clamp fired. The chain reconstructs txInfo.validRange.upperBound from the TX TTL. Agora's ppermitVote synthesizes the expected Voted lock with `posix_time = upperBound` and ponlyLocksUpdated compares it to our output's lock. With a slot mismatch the lock posix_time differs by (default - voting_end) seconds — for a 1799-slot default and a small voting window remainder, this is hundreds-to-thousands of seconds. The mismatch surfaces as a silent UPLC error in the stake validator with no preceding ptrace, exactly matching the 'validator crashed / exited prematurely' chain rejections we've been chasing for two days. Verified hypothesis against working Clarity vote 4f2fac985a08db2349ef2a650bb66ca6cd42fab1ecc5976bb673687666922503: TTL slot 130276129 → posix_ms 1721842420000, Voted.posix_time 1721842420000 — exact match (diff 0 ms). Our failing prop #5 vote 4f2fac98... had TTL.posix_ms = 1778296041000 vs Voted.posix_time 1778294743000 = 1298s mismatch. Fix: introduce explicit `validity_upper_slot` field on ProposalVoteArgs alongside `validity_upper_ms`. Caller sets BOTH from the same source (MCP layer already had this slot in scope at the clamp site). The builder's TTL now uses validity_upper_slot (so the chain computes the same upperBound as our datum embedded). Other builders (cosign / advance / retract_votes) don't write a datum field that depends on slot↔ms conversion, so they're not affected by this bug. Test fixture updated to derive validity_upper_slot from validity_upper_ms via the mainnet shelley-zero constants. |
||
|---|---|---|
| .. | ||
| src | ||
| Cargo.toml | ||