--- a/primitives/data-structs/src/lib.rs +++ b/primitives/data-structs/src/lib.rs @@ -1104,14 +1104,19 @@ } impl PropertyScope { + pub fn prefix(&self) -> &'static [u8] { + match self { + Self::None => b"", + Self::Rmrk => b"rmrk:", + } + } /// Apply scope to property key. pub fn apply(self, key: PropertyKey) -> Result { - let scope_str: &[u8] = match self { - Self::None => return Ok(key), - Self::Rmrk => b"rmrk", - }; - - [scope_str, b":", key.as_slice()] + let prefix = self.prefix(); + if prefix == b"" { + return Ok(key); + } + [prefix, key.as_slice()] .concat() .try_into() .map_err(|_| PropertiesError::PropertyKeyIsTooLong) @@ -1197,12 +1202,6 @@ self.0.contains_key(key) } - fn metadata_encoded_len() -> usize { - // Max length of key length + max length of value length for max properties - // + max length of table size length - (4 * 4) * (MAX_PROPERTIES_PER_ITEM as usize) + 4 - } - /// Check if map contains key with key validation. fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> { if key.is_empty() { @@ -1223,6 +1222,10 @@ pub fn values(&self) -> impl Iterator { self.0.values() } + + pub fn iter(&self) -> impl Iterator { + self.0.iter() + } } impl IntoIterator for PropertiesMap { @@ -1261,19 +1264,30 @@ /// Alias for property permissions map. pub type PropertiesPermissionMap = PropertiesMap; +fn slice_size(data: &[u8]) -> u32 { + scoped_slice_size(PropertyScope::None, data) +} +fn scoped_slice_size(scope: PropertyScope, data: &[u8]) -> u32 { + use codec::Compact; + let prefix = scope.prefix(); + >::encoded_size(&Compact(data.len() as u32 + prefix.len() as u32)) as u32 + + data.len() as u32 + + prefix.len() as u32 +} + /// Wrapper for properties map with consumed space control. #[derive(Encode, Decode, TypeInfo, Clone, PartialEq)] pub struct Properties { map: PropertiesMap, consumed_space: u32, - space_limit: u32, + // May be not zero, previously served as a current S generic + _reserved: u32, } impl MaxEncodedLen for Properties { fn max_encoded_len() -> usize { - >::metadata_encoded_len() - + (u32::max_encoded_len() * 2) - + S as usize + // len of map + len of consumed_space + len of space_limit + u32::max_encoded_len() * 3 + S as usize } } @@ -1289,7 +1303,7 @@ Self { map: PropertiesMap::new(), consumed_space: 0, - space_limit: u32::MAX, + _reserved: 0, } } @@ -1298,8 +1312,8 @@ let value = self.map.remove(key)?; if let Some(ref value) = value { - let value_len = value.len() as u32; - self.consumed_space -= value_len; + let kv_len = slice_size(key) + slice_size(value); + self.consumed_space = self.consumed_space.saturating_sub(kv_len); } Ok(value) @@ -1313,7 +1327,11 @@ /// Recomputes the consumed space for the current properties state. /// Needed to repair a token due to a bug fixed in the [PR #733](https://github.com/UniqueNetwork/unique-chain/pull/773). pub fn recompute_consumed_space(&mut self) { - self.consumed_space = self.map.values().map(|value| value.len() as u32).sum(); + self.consumed_space = self + .map + .iter() + .map(|(key, value)| slice_size(key) + slice_size(value)) + .sum(); } } @@ -1335,23 +1353,21 @@ key: PropertyKey, value: Self::Value, ) -> Result, PropertiesError> { - let value_len = value.len(); + let key_size = scoped_slice_size(scope, &key); + let value_size = slice_size(&value) as u32; - if self.consumed_space as usize + value_len > self.space_limit.min(S) as usize - && !cfg!(feature = "runtime-benchmarks") + if self.consumed_space + value_size + key_size > S && !cfg!(feature = "runtime-benchmarks") { return Err(PropertiesError::NoSpaceForProperty); } - let value_len = value_len as u32; let old_value = self.map.try_scoped_set(scope, key, value)?; - let old_value_len = old_value.as_ref().map(|v| v.len() as u32).unwrap_or(0); - - if value_len > old_value_len { - self.consumed_space += value_len - old_value_len; + if let Some(old_value) = old_value.as_ref() { + let old_value_size = slice_size(&old_value); + self.consumed_space = self.consumed_space.saturating_sub(old_value_size) + value_size; } else { - self.consumed_space -= old_value_len - value_len; + self.consumed_space += key_size + value_size; } Ok(old_value)