Skip to content

Commit

Permalink
[7][15/n][enums/Move] Add flavor to serialized compiled module for ve…
Browse files Browse the repository at this point in the history
…rsions >= 7
  • Loading branch information
tzakian committed May 13, 2024
1 parent a54c659 commit 72e8a84
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 12 deletions.
21 changes: 17 additions & 4 deletions external-crates/move/crates/move-binary-format/src/deserializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2118,16 +2118,29 @@ impl<'a, 'b> VersionedBinary<'a, 'b> {
.with_message("Bad binary header".to_string()));
}
// load binary version
let version = match read_u32(&mut cursor) {
let flavored_version = match read_u32(&mut cursor) {
Ok(v) => v,
Err(_) => {
return Err(PartialVMError::new(StatusCode::MALFORMED)
.with_message("Bad binary header".to_string()));
}
};
if version < binary_config.min_binary_format_version
|| version > u32::min(binary_config.max_binary_format_version, VERSION_MAX)
{

let version = BinaryFlavor::decode_version(flavored_version);
let flavor = BinaryFlavor::decode_flavor(flavored_version);

// Version is below minimum supported version
if version < binary_config.min_binary_format_version {
return Err(PartialVMError::new(StatusCode::UNKNOWN_VERSION));
}

// Version is greater than maximum supported version
if version > u32::min(binary_config.max_binary_format_version, VERSION_MAX) {
return Err(PartialVMError::new(StatusCode::UNKNOWN_VERSION));
}

// Bad flavor to the version: for version 7 and above, only SUI_FLAVOR is supported
if version >= VERSION_7 && flavor != Some(BinaryFlavor::SUI_FLAVOR) {
return Err(PartialVMError::new(StatusCode::UNKNOWN_VERSION));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,54 @@ use std::{
mem::size_of,
};

// Static assertions about the encoding of the flavor into the version of the binary format.
const _: () = {
let x = BinaryFlavor::shift_and_flavor(0u32);
assert!(x == 0x0500_0000u32);
assert!(BinaryFlavor::mask_and_shift_to_unflavor(x) == BinaryFlavor::SUI_FLAVOR);
};

/// Encoding of a the flavor into the version of the binary format for versions >= 7.
pub struct BinaryFlavor;
impl BinaryFlavor {
pub const FLAVOR_MASK: u32 = 0xFF00_0000;
pub const VERSION_MASK: u32 = 0x00FF_FFFF;
// The Sui flavor is 0x05
pub const SUI_FLAVOR: u8 = 0x05;
const SHIFT_AMOUNT: u8 = 24;

pub fn encode_version(unflavored_version: u32) -> u32 {
if unflavored_version <= VERSION_6 {
return unflavored_version;
}

debug_assert!(unflavored_version & Self::VERSION_MASK == unflavored_version);
Self::shift_and_flavor(unflavored_version)
}

pub fn decode_version(flavored_version: u32) -> u32 {
if flavored_version <= VERSION_6 {
return flavored_version;
}
flavored_version & Self::VERSION_MASK
}

pub fn decode_flavor(flavored_version: u32) -> Option<u8> {
if flavored_version <= VERSION_6 {
return None;
}
Some(Self::mask_and_shift_to_unflavor(flavored_version))
}

const fn mask_and_shift_to_unflavor(flavored: u32) -> u8 {
((flavored & Self::FLAVOR_MASK) >> Self::SHIFT_AMOUNT) as u8
}

const fn shift_and_flavor(unflavored: u32) -> u32 {
(Self::SUI_FLAVOR as u32) << Self::SHIFT_AMOUNT | unflavored
}
}

/// Constant values for the binary format header.
///
/// The binary header is magic + version info + table count.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1108,7 +1108,7 @@ impl CommonSerializer {

fn serialize_header(&mut self, binary: &mut BinaryData) -> Result<()> {
serialize_magic(binary)?;
write_u32(binary, self.major_version)?;
write_u32(binary, BinaryFlavor::encode_version(self.major_version))?;
Ok(())
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,22 @@ proptest! {
}
}
}

#[test]
fn test_flavor() {
for i in 1..=6 {
let encoded = BinaryFlavor::encode_version(i);
assert_eq!(encoded, i);
assert_eq!(BinaryFlavor::decode_version(encoded), i);
assert_eq!(BinaryFlavor::decode_flavor(encoded), None);
}

for i in 7..1024 {
let flavored = BinaryFlavor::encode_version(i);
assert_eq!(BinaryFlavor::decode_version(flavored), i);
assert_eq!(
BinaryFlavor::decode_flavor(flavored),
Some(BinaryFlavor::SUI_FLAVOR)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -411,3 +411,45 @@ fn deserialize_empty_enum_fails() {
CompiledModule::deserialize_with_config(&bin, &BinaryConfig::with_extraneous_bytes_check(true))
.unwrap_err();
}

#[test]
fn serialize_deserialize_v6_no_flavor() {
let module = basic_test_module();
let mut bin = vec![];
module.serialize_with_version(VERSION_6, &mut bin).unwrap();
let v6_bytes = VERSION_6.to_le_bytes();
let v6_flavor_bytes = BinaryFlavor::encode_version(VERSION_6).to_le_bytes();
// assert that no flavoring is added to v6
assert_eq!(v6_bytes, v6_flavor_bytes);
assert_eq!(
bin[BinaryConstants::MOVE_MAGIC_SIZE..BinaryConstants::MOVE_MAGIC_SIZE + v6_bytes.len()],
v6_bytes
);
let module = CompiledModule::deserialize_with_defaults(&bin).unwrap();
assert_eq!(module.version, VERSION_6);
}

#[test]
fn serialize_deserialize_v7_with_no_flavor() {
let module = basic_test_module();
let mut bin = vec![];
module.serialize_with_version(VERSION_7, &mut bin).unwrap();
let v7_bytes = VERSION_7.to_le_bytes();
// Override the version bytes to not have the flavor
for (i, b) in v7_bytes.iter().enumerate() {
bin[i + BinaryConstants::MOVE_MAGIC_SIZE] = *b;
}
// Deserialization will now fail because the version is not encoded with the flavor and the
// version is >= 7.
let x = CompiledModule::deserialize_with_defaults(&bin).unwrap_err();
assert_eq!(x.major_status(), StatusCode::UNKNOWN_VERSION);
}

#[test]
fn serialize_deserialize_v7_with_flavor() {
let module = basic_test_module_with_enum();
let mut bin = vec![];
module.serialize_with_version(VERSION_7, &mut bin).unwrap();
let x = CompiledModule::deserialize_with_defaults(&bin).unwrap();
assert_eq!(x, module);
}
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ fn serialization_upgrades_version() {
assert!(module
.serialize_with_version(VERSION_MAX, &mut m_bytes)
.is_ok());
let v_max_bytes = VERSION_MAX.to_le_bytes();
let v_6_bytes = VERSION_6.to_le_bytes();
let v_max_bytes = BinaryFlavor::encode_version(VERSION_MAX).to_le_bytes();
let v_6_bytes = BinaryFlavor::encode_version(VERSION_6).to_le_bytes();
assert_eq!(
m_bytes[BinaryConstants::MOVE_MAGIC_SIZE
..BinaryConstants::MOVE_MAGIC_SIZE + v_max_bytes.len()],
Expand All @@ -174,17 +174,51 @@ fn serialization_upgrades_version() {
);
}

// Test that the serialization version matches the module's version if no override is provided.
#[test]
fn serialization_upgrades_version_no_override() {
let mut module = basic_test_module();
let module = basic_test_module();
let mut m_bytes = vec![];
module.version = VERSION_6;
assert!(module.serialize(&mut m_bytes).is_ok());
let v_max_bytes = VERSION_MAX.to_le_bytes();
assert!(module
.serialize_with_version(module.version, &mut m_bytes)
.is_ok());
let v_max_bytes = BinaryFlavor::encode_version(VERSION_MAX).to_le_bytes();
assert_eq!(
m_bytes[BinaryConstants::MOVE_MAGIC_SIZE
..BinaryConstants::MOVE_MAGIC_SIZE + v_max_bytes.len()],
v_max_bytes
);
}

#[test]
fn serialize_v6_has_no_flavor() {
let module = basic_test_module();
let mut bin = vec![];
module.serialize_with_version(VERSION_6, &mut bin).unwrap();
let v6_bytes = VERSION_6.to_le_bytes();
let v6_flavor_bytes = BinaryFlavor::encode_version(VERSION_6).to_le_bytes();
// assert that no flavoring is added to v6
assert_eq!(v6_bytes, v6_flavor_bytes);
assert_eq!(
bin[BinaryConstants::MOVE_MAGIC_SIZE..BinaryConstants::MOVE_MAGIC_SIZE + v6_bytes.len()],
v6_bytes
);
}

#[test]
fn serialize_v7_has_flavor() {
let module = basic_test_module();
let mut bin = vec![];
module.serialize_with_version(VERSION_7, &mut bin).unwrap();
let v7_flavored_bytes = BinaryFlavor::encode_version(VERSION_7).to_le_bytes();
let v7_unflavored_bytes = VERSION_7.to_le_bytes();
assert_eq!(
bin[BinaryConstants::MOVE_MAGIC_SIZE
..BinaryConstants::MOVE_MAGIC_SIZE + v7_flavored_bytes.len()],
v7_flavored_bytes
);
assert_ne!(
bin[BinaryConstants::MOVE_MAGIC_SIZE
..BinaryConstants::MOVE_MAGIC_SIZE + v7_unflavored_bytes.len()],
v7_unflavored_bytes
);
}

0 comments on commit 72e8a84

Please sign in to comment.