diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/type_names.exp b/crates/sui-adapter-transactional-tests/tests/upgrade/type_names.exp index b7d448a884cc0..3198fa30144ce 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/type_names.exp +++ b/crates/sui-adapter-transactional-tests/tests/upgrade/type_names.exp @@ -68,70 +68,70 @@ Contents: A0::m::Canary { }, }, addr: vector[ - 100u8, - 49u8, 57u8, - 51u8, - 56u8, - 100u8, - 97u8, - 52u8, - 53u8, - 102u8, + 55u8, + 98u8, 99u8, - 56u8, - 50u8, - 53u8, + 57u8, 98u8, + 98u8, + 51u8, + 49u8, 56u8, - 56u8, - 99u8, - 102u8, + 55u8, + 53u8, 52u8, - 51u8, - 51u8, - 99u8, + 97u8, 100u8, - 56u8, + 53u8, + 49u8, + 52u8, 98u8, - 97u8, 98u8, - 97u8, - 52u8, - 52u8, - 51u8, + 49u8, 99u8, - 56u8, + 54u8, 99u8, + 52u8, + 52u8, + 49u8, + 98u8, 56u8, - 100u8, + 51u8, + 97u8, 53u8, - 100u8, - 49u8, + 55u8, 57u8, - 101u8, - 53u8, - 54u8, + 55u8, + 49u8, 98u8, - 101u8, + 56u8, + 100u8, + 56u8, 48u8, + 53u8, + 52u8, 101u8, - 54u8, - 48u8, - 97u8, + 101u8, + 99u8, 102u8, + 50u8, + 98u8, 54u8, + 48u8, + 98u8, + 51u8, 52u8, - 56u8, - 53u8, - 101u8, 54u8, - 97u8, - 48u8, + 101u8, 57u8, 99u8, + 52u8, + 57u8, + 57u8, + 56u8, + 56u8, 99u8, - 50u8, ], } @@ -145,70 +145,70 @@ Contents: A0::m::Canary { }, }, addr: vector[ - 100u8, - 49u8, 57u8, - 51u8, - 56u8, - 100u8, - 97u8, - 52u8, - 53u8, - 102u8, + 55u8, + 98u8, 99u8, - 56u8, - 50u8, - 53u8, + 57u8, 98u8, + 98u8, + 51u8, + 49u8, 56u8, - 56u8, - 99u8, - 102u8, + 55u8, + 53u8, 52u8, - 51u8, - 51u8, - 99u8, + 97u8, 100u8, - 56u8, + 53u8, + 49u8, + 52u8, 98u8, - 97u8, 98u8, - 97u8, - 52u8, - 52u8, - 51u8, + 49u8, 99u8, - 56u8, + 54u8, 99u8, + 52u8, + 52u8, + 49u8, + 98u8, 56u8, - 100u8, + 51u8, + 97u8, 53u8, - 100u8, - 49u8, + 55u8, 57u8, - 101u8, - 53u8, - 54u8, + 55u8, + 49u8, 98u8, - 101u8, + 56u8, + 100u8, + 56u8, 48u8, + 53u8, + 52u8, 101u8, - 54u8, - 48u8, - 97u8, + 101u8, + 99u8, 102u8, + 50u8, + 98u8, 54u8, + 48u8, + 98u8, + 51u8, 52u8, - 56u8, - 53u8, - 101u8, 54u8, - 97u8, - 48u8, + 101u8, 57u8, 99u8, + 52u8, + 57u8, + 57u8, + 56u8, + 56u8, 99u8, - 50u8, ], } @@ -222,70 +222,70 @@ Contents: A0::m::Canary { }, }, addr: vector[ - 100u8, - 49u8, 57u8, - 51u8, - 56u8, - 100u8, - 97u8, - 52u8, - 53u8, - 102u8, + 55u8, + 98u8, 99u8, - 56u8, - 50u8, - 53u8, + 57u8, 98u8, + 98u8, + 51u8, + 49u8, 56u8, - 56u8, - 99u8, - 102u8, + 55u8, + 53u8, 52u8, - 51u8, - 51u8, - 99u8, + 97u8, 100u8, - 56u8, + 53u8, + 49u8, + 52u8, 98u8, - 97u8, 98u8, - 97u8, - 52u8, - 52u8, - 51u8, + 49u8, 99u8, - 56u8, + 54u8, 99u8, + 52u8, + 52u8, + 49u8, + 98u8, 56u8, - 100u8, + 51u8, + 97u8, 53u8, - 100u8, - 49u8, + 55u8, 57u8, - 101u8, - 53u8, - 54u8, + 55u8, + 49u8, 98u8, - 101u8, + 56u8, + 100u8, + 56u8, 48u8, + 53u8, + 52u8, 101u8, - 54u8, - 48u8, - 97u8, + 101u8, + 99u8, 102u8, + 50u8, + 98u8, 54u8, + 48u8, + 98u8, + 51u8, 52u8, - 56u8, - 53u8, - 101u8, 54u8, - 97u8, - 48u8, + 101u8, 57u8, 99u8, + 52u8, + 57u8, + 57u8, + 56u8, + 56u8, 99u8, - 50u8, ], } @@ -299,70 +299,70 @@ Contents: A0::m::Canary { }, }, addr: vector[ - 52u8, - 52u8, - 56u8, - 57u8, - 50u8, + 54u8, 99u8, - 53u8, - 100u8, + 97u8, + 49u8, 57u8, + 52u8, + 98u8, + 98u8, + 57u8, + 54u8, + 54u8, + 48u8, + 48u8, + 52u8, + 48u8, + 101u8, + 54u8, + 52u8, + 102u8, 53u8, 99u8, 49u8, - 51u8, - 51u8, - 48u8, - 48u8, + 54u8, + 97u8, + 53u8, + 56u8, + 102u8, + 49u8, 48u8, - 57u8, + 101u8, + 97u8, + 101u8, 98u8, + 54u8, 50u8, - 55u8, + 54u8, 48u8, - 51u8, - 52u8, - 55u8, - 101u8, + 102u8, 49u8, + 99u8, + 53u8, + 101u8, + 55u8, 55u8, - 56u8, - 97u8, - 52u8, 48u8, - 51u8, 56u8, - 53u8, - 49u8, + 48u8, 54u8, - 100u8, - 57u8, - 98u8, - 57u8, - 53u8, + 55u8, + 52u8, + 50u8, + 101u8, 99u8, - 54u8, + 49u8, + 52u8, + 102u8, 55u8, - 57u8, - 53u8, - 53u8, 102u8, 57u8, 55u8, - 55u8, - 56u8, - 102u8, - 53u8, - 51u8, - 98u8, 101u8, - 51u8, - 97u8, - 100u8, - 53u8, + 54u8, 48u8, - 102u8, + 56u8, ], } @@ -376,70 +376,70 @@ Contents: A0::m::Canary { }, }, addr: vector[ - 100u8, - 49u8, 57u8, - 51u8, - 56u8, - 100u8, - 97u8, - 52u8, - 53u8, - 102u8, + 55u8, + 98u8, 99u8, - 56u8, - 50u8, - 53u8, + 57u8, 98u8, + 98u8, + 51u8, + 49u8, 56u8, - 56u8, - 99u8, - 102u8, + 55u8, + 53u8, 52u8, - 51u8, - 51u8, - 99u8, + 97u8, 100u8, - 56u8, + 53u8, + 49u8, + 52u8, 98u8, - 97u8, 98u8, - 97u8, - 52u8, - 52u8, - 51u8, + 49u8, 99u8, - 56u8, + 54u8, 99u8, + 52u8, + 52u8, + 49u8, + 98u8, 56u8, - 100u8, + 51u8, + 97u8, 53u8, - 100u8, - 49u8, + 55u8, 57u8, - 101u8, - 53u8, - 54u8, + 55u8, + 49u8, 98u8, - 101u8, + 56u8, + 100u8, + 56u8, 48u8, + 53u8, + 52u8, 101u8, - 54u8, - 48u8, - 97u8, + 101u8, + 99u8, 102u8, + 50u8, + 98u8, 54u8, + 48u8, + 98u8, + 51u8, 52u8, - 56u8, - 53u8, - 101u8, 54u8, - 97u8, - 48u8, + 101u8, 57u8, 99u8, + 52u8, + 57u8, + 57u8, + 56u8, + 56u8, 99u8, - 50u8, ], } @@ -453,70 +453,70 @@ Contents: A0::m::Canary { }, }, addr: vector[ - 100u8, - 49u8, 57u8, - 51u8, - 56u8, - 100u8, - 97u8, - 52u8, - 53u8, - 102u8, + 55u8, + 98u8, 99u8, - 56u8, - 50u8, - 53u8, + 57u8, 98u8, + 98u8, + 51u8, + 49u8, 56u8, - 56u8, - 99u8, - 102u8, + 55u8, + 53u8, 52u8, - 51u8, - 51u8, - 99u8, + 97u8, 100u8, - 56u8, + 53u8, + 49u8, + 52u8, 98u8, - 97u8, 98u8, - 97u8, - 52u8, - 52u8, - 51u8, + 49u8, 99u8, - 56u8, + 54u8, 99u8, + 52u8, + 52u8, + 49u8, + 98u8, 56u8, - 100u8, + 51u8, + 97u8, 53u8, - 100u8, - 49u8, + 55u8, 57u8, - 101u8, - 53u8, - 54u8, + 55u8, + 49u8, 98u8, - 101u8, + 56u8, + 100u8, + 56u8, 48u8, + 53u8, + 52u8, 101u8, - 54u8, - 48u8, - 97u8, + 101u8, + 99u8, 102u8, + 50u8, + 98u8, 54u8, + 48u8, + 98u8, + 51u8, 52u8, - 56u8, - 53u8, - 101u8, 54u8, - 97u8, - 48u8, + 101u8, 57u8, 99u8, + 52u8, + 57u8, + 57u8, + 56u8, + 56u8, 99u8, - 50u8, ], } @@ -530,70 +530,70 @@ Contents: A0::m::Canary { }, }, addr: vector[ - 100u8, - 49u8, 57u8, - 51u8, - 56u8, - 100u8, - 97u8, - 52u8, - 53u8, - 102u8, + 55u8, + 98u8, 99u8, - 56u8, - 50u8, - 53u8, + 57u8, 98u8, + 98u8, + 51u8, + 49u8, 56u8, - 56u8, - 99u8, - 102u8, + 55u8, + 53u8, 52u8, - 51u8, - 51u8, - 99u8, + 97u8, 100u8, - 56u8, + 53u8, + 49u8, + 52u8, 98u8, - 97u8, 98u8, - 97u8, - 52u8, - 52u8, - 51u8, + 49u8, 99u8, - 56u8, + 54u8, 99u8, + 52u8, + 52u8, + 49u8, + 98u8, 56u8, - 100u8, + 51u8, + 97u8, 53u8, - 100u8, - 49u8, + 55u8, 57u8, - 101u8, - 53u8, - 54u8, + 55u8, + 49u8, 98u8, - 101u8, + 56u8, + 100u8, + 56u8, 48u8, + 53u8, + 52u8, 101u8, - 54u8, - 48u8, - 97u8, + 101u8, + 99u8, 102u8, + 50u8, + 98u8, 54u8, + 48u8, + 98u8, + 51u8, 52u8, - 56u8, - 53u8, - 101u8, 54u8, - 97u8, - 48u8, + 101u8, 57u8, 99u8, + 52u8, + 57u8, + 57u8, + 56u8, + 56u8, 99u8, - 50u8, ], } @@ -607,69 +607,69 @@ Contents: A0::m::Canary { }, }, addr: vector[ - 52u8, - 52u8, - 56u8, - 57u8, - 50u8, + 54u8, 99u8, - 53u8, - 100u8, + 97u8, + 49u8, 57u8, + 52u8, + 98u8, + 98u8, + 57u8, + 54u8, + 54u8, + 48u8, + 48u8, + 52u8, + 48u8, + 101u8, + 54u8, + 52u8, + 102u8, 53u8, 99u8, 49u8, - 51u8, - 51u8, - 48u8, - 48u8, + 54u8, + 97u8, + 53u8, + 56u8, + 102u8, + 49u8, 48u8, - 57u8, + 101u8, + 97u8, + 101u8, 98u8, + 54u8, 50u8, - 55u8, + 54u8, 48u8, - 51u8, - 52u8, - 55u8, - 101u8, + 102u8, 49u8, + 99u8, + 53u8, + 101u8, + 55u8, 55u8, - 56u8, - 97u8, - 52u8, 48u8, - 51u8, 56u8, - 53u8, - 49u8, + 48u8, 54u8, - 100u8, - 57u8, - 98u8, - 57u8, - 53u8, + 55u8, + 52u8, + 50u8, + 101u8, 99u8, - 54u8, + 49u8, + 52u8, + 102u8, 55u8, - 57u8, - 53u8, - 53u8, 102u8, 57u8, 55u8, - 55u8, - 56u8, - 102u8, - 53u8, - 51u8, - 98u8, 101u8, - 51u8, - 97u8, - 100u8, - 53u8, + 54u8, 48u8, - 102u8, + 56u8, ], } diff --git a/external-crates/move/crates/move-binary-format/src/deserializer.rs b/external-crates/move/crates/move-binary-format/src/deserializer.rs index 6e7a32a8cb1f7..ab3c8db8b2122 100644 --- a/external-crates/move/crates/move-binary-format/src/deserializer.rs +++ b/external-crates/move/crates/move-binary-format/src/deserializer.rs @@ -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)); } diff --git a/external-crates/move/crates/move-binary-format/src/file_format_common.rs b/external-crates/move/crates/move-binary-format/src/file_format_common.rs index 80b0392477eda..7c81c755a012a 100644 --- a/external-crates/move/crates/move-binary-format/src/file_format_common.rs +++ b/external-crates/move/crates/move-binary-format/src/file_format_common.rs @@ -19,6 +19,57 @@ 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); + // Make sure that the flavoring is added in the correct position in the u32. + // It should always be `0x05XX_XXXX` where `XX_XXXX` is the version digits. + assert!(x == 0x0500_0000u32); + // Make sure that the flavoring is extracted correctly. + 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 { + 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. diff --git a/external-crates/move/crates/move-binary-format/src/serializer.rs b/external-crates/move/crates/move-binary-format/src/serializer.rs index 07428c2d36734..2d5a362e23914 100644 --- a/external-crates/move/crates/move-binary-format/src/serializer.rs +++ b/external-crates/move/crates/move-binary-format/src/serializer.rs @@ -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(()) } diff --git a/external-crates/move/crates/move-binary-format/src/unit_tests/binary_tests.rs b/external-crates/move/crates/move-binary-format/src/unit_tests/binary_tests.rs index baac239cd0a6f..888635dbbd192 100644 --- a/external-crates/move/crates/move-binary-format/src/unit_tests/binary_tests.rs +++ b/external-crates/move/crates/move-binary-format/src/unit_tests/binary_tests.rs @@ -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) + ); + } +} diff --git a/external-crates/move/crates/move-binary-format/src/unit_tests/deserializer_tests.rs b/external-crates/move/crates/move-binary-format/src/unit_tests/deserializer_tests.rs index 8d049eae0ee60..d6d220c88b1c2 100644 --- a/external-crates/move/crates/move-binary-format/src/unit_tests/deserializer_tests.rs +++ b/external-crates/move/crates/move-binary-format/src/unit_tests/deserializer_tests.rs @@ -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); +} diff --git a/external-crates/move/crates/move-binary-format/src/unit_tests/serializer_tests.rs b/external-crates/move/crates/move-binary-format/src/unit_tests/serializer_tests.rs index 1f08ec0820247..070383887c077 100644 --- a/external-crates/move/crates/move-binary-format/src/unit_tests/serializer_tests.rs +++ b/external-crates/move/crates/move-binary-format/src/unit_tests/serializer_tests.rs @@ -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()], @@ -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 + ); +}