test(dao): live-stake round-trip checks decoded struct, not bytes

The first cut asserted byte-exact CBOR round-trip, but pallas-codec
emits def-arrays (`81`) while chain CBOR uses indef (`9f...ff`).
Both are Plutus-structurally-equal — validator's `==` accepts
either — but Vec<u8> equality doesn't. Switch to assert
`decode(reencode(decode(cbor)))` equals `decode(cbor)` instead.
That's the actual validator-relevant invariant: typed fields
preserved, no silent drift.
This commit is contained in:
Sulkta 2026-05-06 08:53:04 -07:00
parent 6f935b58b2
commit 6406a170b0

View file

@ -364,17 +364,18 @@ mod tests {
assert!(stake.delegated_to.is_none()); assert!(stake.delegated_to.is_none());
assert!(stake.locked_by.is_empty()); assert!(stake.locked_by.is_empty());
// Round-trip — encoding our decoded stake should give back the // Round-trip via StakeDatum. Encode our decoded stake, decode
// exact bytes we started with. This is the critical property: // the result, assert the struct survives unchanged. We CAN'T
// any drift in field order, integer encoding, or empty-list // assert byte-exact CBOR because pallas-codec emits def-encoded
// shape would break the validator's bit-exact `==` check on // arrays while chain CBOR uses indef (`9f ... ff`) — both are
// mutated stake outputs. // Plutus-structurally-equal so the validator's `==` accepts
// either. The meaningful invariant is: round-trip preserves
// every typed field, no silent drift across encode/decode.
let re_encoded = pallas_codec::minicbor::to_vec(&stake.to_plutus_data().unwrap()).unwrap(); let re_encoded = pallas_codec::minicbor::to_vec(&stake.to_plutus_data().unwrap()).unwrap();
assert_eq!( let re_pd: pallas_primitives::PlutusData =
hex::encode(&re_encoded), pallas_codec::minicbor::decode(&re_encoded).unwrap();
cbor_hex, let round_tripped = StakeDatum::from_plutus_data(&re_pd).expect("re-decode");
"round-trip CBOR diverged" assert_eq!(round_tripped, stake, "round-trip lost a field");
);
} }
/// Same shape as `decodes_live_stake_datum` but for a second /// Same shape as `decodes_live_stake_datum` but for a second
@ -396,7 +397,10 @@ mod tests {
assert!(stake.locked_by.is_empty()); assert!(stake.locked_by.is_empty());
let re_encoded = pallas_codec::minicbor::to_vec(&stake.to_plutus_data().unwrap()).unwrap(); let re_encoded = pallas_codec::minicbor::to_vec(&stake.to_plutus_data().unwrap()).unwrap();
assert_eq!(hex::encode(&re_encoded), cbor_hex, "round-trip CBOR diverged"); let re_pd: pallas_primitives::PlutusData =
pallas_codec::minicbor::decode(&re_encoded).unwrap();
let round_tripped = StakeDatum::from_plutus_data(&re_pd).expect("re-decode");
assert_eq!(round_tripped, stake, "round-trip lost a field");
} }
#[test] #[test]