Skip to content

Commit 3b7d1b1

Browse files
committed
proptest rewrite
1 parent 8f34c20 commit 3b7d1b1

14 files changed

Lines changed: 1572 additions & 1481 deletions

File tree

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pinocchio/interface/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ homepage = { workspace = true }
88
license = { workspace = true }
99

1010
[dependencies]
11-
wincode = { git = "https://github.com/anza-xyz/wincode.git", branch = "master", default-features = false, features = ["derive"] }
11+
# TODO: Waiting on 0.3.0 to be released
12+
wincode = { git = "https://github.com/anza-xyz/wincode.git", rev = "fa70c7c7c13885085f743e4f01deb1a4de0b64fb", default-features = false, features = ["derive"] }
1213

1314
[dev-dependencies]
1415
bincode = "1.3.3"

pinocchio/interface/src/state/writer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ pub enum StakeStateV2ViewMut<'a> {
105105
}
106106

107107
impl<'a> StakeStateV2ViewMut<'a> {
108-
pub fn from_bytes_mut(data: &'a mut [u8]) -> Result<Self, StakeStateError> {
108+
pub(super) fn from_bytes_mut(data: &'a mut [u8]) -> Result<Self, StakeStateError> {
109109
if data.len() < size_of::<StakeStateV2Layout>() {
110110
return Err(StakeStateError::UnexpectedEof);
111111
}

pinocchio/interface/tests/abi.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
mod helpers;
2+
3+
use {
4+
bincode::Options,
5+
helpers::*,
6+
p_stake_interface::state::{StakeStateV2, StakeStateV2Layout, StakeStateV2View},
7+
proptest::prelude::*,
8+
solana_stake_interface::state::StakeStateV2 as LegacyStakeStateV2,
9+
wincode::ZeroCopy,
10+
};
11+
12+
fn assert_legacy_and_view_agree(bytes: &[u8]) {
13+
let legacy: LegacyStakeStateV2 = bincode_opts().deserialize(bytes).unwrap();
14+
let view = StakeStateV2::from_bytes(bytes).unwrap();
15+
16+
match (legacy, view) {
17+
(LegacyStakeStateV2::Uninitialized, StakeStateV2View::Uninitialized) => {}
18+
(LegacyStakeStateV2::RewardsPool, StakeStateV2View::RewardsPool) => {}
19+
(LegacyStakeStateV2::Initialized(legacy_meta), StakeStateV2View::Initialized(meta)) => {
20+
assert_meta_compat(meta, &legacy_meta);
21+
}
22+
(
23+
LegacyStakeStateV2::Stake(legacy_meta, legacy_stake, legacy_flags),
24+
StakeStateV2View::Stake { meta, stake },
25+
) => {
26+
assert_meta_compat(meta, &legacy_meta);
27+
assert_stake_compat(stake, &legacy_stake);
28+
29+
// ABI: stake_flags byte must match legacy exactly.
30+
let layout = StakeStateV2Layout::from_bytes(bytes).unwrap();
31+
assert_eq!(layout.stake_flags, stake_flags_byte(&legacy_flags));
32+
}
33+
34+
(o, v) => panic!("variant mismatch legacy={o:?} new={v:?}"),
35+
}
36+
}
37+
38+
proptest! {
39+
#![proptest_config(ProptestConfig::with_cases(10000))]
40+
41+
// legacy bincode == new layout wincode bytes
42+
#[test]
43+
fn prop_wincode_roundtrips_legacy_bytes(legacy in arb_legacy_state()) {
44+
let expected = serialize_legacy(&legacy);
45+
prop_assert_eq!(expected.len(), LAYOUT_LEN);
46+
47+
let new_layout = StakeStateV2Layout::from_bytes(&expected[..]).unwrap();
48+
let mut actual = [0u8; 200];
49+
wincode::serialize_into(&mut actual.as_mut_slice(), new_layout).unwrap();
50+
51+
prop_assert_eq!(expected.as_slice(), &actual);
52+
}
53+
54+
// both the legacy decoder and zero-copy view interpret trailing bytes the same
55+
#[test]
56+
fn prop_unpadded_legacy_prefix_is_compatible(legacy in arb_legacy_state(), mut tail in any::<[u8; 200]>()) {
57+
let prefix = serialize_legacy_unpadded(&legacy);
58+
tail[..prefix.len()].copy_from_slice(&prefix);
59+
assert_legacy_and_view_agree(&tail[..]);
60+
}
61+
62+
// arbitrary 200-byte blobs with a valid tag must parse identically in legacy bincode and the zero-copy view
63+
#[test]
64+
fn prop_any_200_bytes_with_valid_tag_legacy_and_new_agree(mut bytes in any::<[u8; 200]>(), tag in 0u32..=3u32) {
65+
bytes[..4].copy_from_slice(&tag.to_le_bytes());
66+
assert_legacy_and_view_agree(&bytes[..]);
67+
}
68+
}

0 commit comments

Comments
 (0)