git.delta.rocks / unique-network / refs/commits / 5667e2a82ef1

difftreelog

refactor account for key sizes in Properties

Yaroslav Bolyukin2023-03-24parent: #87bc2c4.patch.diff
in: master

1 file changed

modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
1104}1104}
11051105
1106impl PropertyScope {1106impl PropertyScope {
1107 pub fn prefix(&self) -> &'static [u8] {
1108 match self {
1109 Self::None => b"",
1110 Self::Rmrk => b"rmrk:",
1111 }
1112 }
1107 /// Apply scope to property key.1113 /// Apply scope to property key.
1108 pub fn apply(self, key: PropertyKey) -> Result<PropertyKey, PropertiesError> {1114 pub fn apply(self, key: PropertyKey) -> Result<PropertyKey, PropertiesError> {
1109 let scope_str: &[u8] = match self {1115 let prefix = self.prefix();
1116 if prefix == b"" {
1110 Self::None => return Ok(key),1117 return Ok(key);
1111 Self::Rmrk => b"rmrk",
1112 };1118 }
1113
1114 [scope_str, b":", key.as_slice()]1119 [prefix, key.as_slice()]
1115 .concat()1120 .concat()
1116 .try_into()1121 .try_into()
1117 .map_err(|_| PropertiesError::PropertyKeyIsTooLong)1122 .map_err(|_| PropertiesError::PropertyKeyIsTooLong)
1197 self.0.contains_key(key)1202 self.0.contains_key(key)
1198 }1203 }
1199
1200 fn metadata_encoded_len() -> usize {
1201 // Max length of key length + max length of value length for max properties
1202 // + max length of table size length
1203 (4 * 4) * (MAX_PROPERTIES_PER_ITEM as usize) + 4
1204 }
12051204
1206 /// Check if map contains key with key validation.1205 /// Check if map contains key with key validation.
1207 fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {1206 fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {
1224 self.0.values()1223 self.0.values()
1225 }1224 }
1225
1226 pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &Value)> {
1227 self.0.iter()
1228 }
1226}1229}
12271230
1228impl<Value> IntoIterator for PropertiesMap<Value> {1231impl<Value> IntoIterator for PropertiesMap<Value> {
1261/// Alias for property permissions map.1264/// Alias for property permissions map.
1262pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;1265pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;
1266
1267fn slice_size(data: &[u8]) -> u32 {
1268 scoped_slice_size(PropertyScope::None, data)
1269}
1270fn scoped_slice_size(scope: PropertyScope, data: &[u8]) -> u32 {
1271 use codec::Compact;
1272 let prefix = scope.prefix();
1273 <Compact<u32>>::encoded_size(&Compact(data.len() as u32 + prefix.len() as u32)) as u32
1274 + data.len() as u32
1275 + prefix.len() as u32
1276}
12631277
1264/// Wrapper for properties map with consumed space control.1278/// Wrapper for properties map with consumed space control.
1265#[derive(Encode, Decode, TypeInfo, Clone, PartialEq)]1279#[derive(Encode, Decode, TypeInfo, Clone, PartialEq)]
1266pub struct Properties<const S: u32> {1280pub struct Properties<const S: u32> {
1267 map: PropertiesMap<PropertyValue>,1281 map: PropertiesMap<PropertyValue>,
1268 consumed_space: u32,1282 consumed_space: u32,
1283 // May be not zero, previously served as a current S generic
1269 space_limit: u32,1284 _reserved: u32,
1270}1285}
12711286
1272impl<const S: u32> MaxEncodedLen for Properties<S> {1287impl<const S: u32> MaxEncodedLen for Properties<S> {
1273 fn max_encoded_len() -> usize {1288 fn max_encoded_len() -> usize {
1274 <PropertiesMap<PropertyValue>>::metadata_encoded_len()1289 // len of map + len of consumed_space + len of space_limit
1275 + (u32::max_encoded_len() * 2)1290 u32::max_encoded_len() * 3 + S as usize
1276 + S as usize
1277 }1291 }
1278}1292}
1289 Self {1303 Self {
1290 map: PropertiesMap::new(),1304 map: PropertiesMap::new(),
1291 consumed_space: 0,1305 consumed_space: 0,
1292 space_limit: u32::MAX,1306 _reserved: 0,
1293 }1307 }
1294 }1308 }
12951309
1298 let value = self.map.remove(key)?;1312 let value = self.map.remove(key)?;
12991313
1300 if let Some(ref value) = value {1314 if let Some(ref value) = value {
1301 let value_len = value.len() as u32;1315 let kv_len = slice_size(key) + slice_size(value);
1302 self.consumed_space -= value_len;1316 self.consumed_space = self.consumed_space.saturating_sub(kv_len);
1303 }1317 }
13041318
1305 Ok(value)1319 Ok(value)
1313 /// Recomputes the consumed space for the current properties state.1327 /// Recomputes the consumed space for the current properties state.
1314 /// Needed to repair a token due to a bug fixed in the [PR #733](https://github.com/UniqueNetwork/unique-chain/pull/773).1328 /// Needed to repair a token due to a bug fixed in the [PR #733](https://github.com/UniqueNetwork/unique-chain/pull/773).
1315 pub fn recompute_consumed_space(&mut self) {1329 pub fn recompute_consumed_space(&mut self) {
1316 self.consumed_space = self.map.values().map(|value| value.len() as u32).sum();1330 self.consumed_space = self
1331 .map
1332 .iter()
1333 .map(|(key, value)| slice_size(key) + slice_size(value))
1334 .sum();
1317 }1335 }
1318}1336}
1335 key: PropertyKey,1353 key: PropertyKey,
1336 value: Self::Value,1354 value: Self::Value,
1337 ) -> Result<Option<Self::Value>, PropertiesError> {1355 ) -> Result<Option<Self::Value>, PropertiesError> {
1356 let key_size = scoped_slice_size(scope, &key);
1338 let value_len = value.len();1357 let value_size = slice_size(&value) as u32;
13391358
1340 if self.consumed_space as usize + value_len > self.space_limit.min(S) as usize1359 if self.consumed_space + value_size + key_size > S && !cfg!(feature = "runtime-benchmarks")
1341 && !cfg!(feature = "runtime-benchmarks")
1342 {1360 {
1343 return Err(PropertiesError::NoSpaceForProperty);1361 return Err(PropertiesError::NoSpaceForProperty);
1344 }1362 }
13451363
1346 let value_len = value_len as u32;
1347 let old_value = self.map.try_scoped_set(scope, key, value)?;1364 let old_value = self.map.try_scoped_set(scope, key, value)?;
13481365
1349 let old_value_len = old_value.as_ref().map(|v| v.len() as u32).unwrap_or(0);1366 if let Some(old_value) = old_value.as_ref() {
13501367 let old_value_size = slice_size(&old_value);
1351 if value_len > old_value_len {
1352 self.consumed_space += value_len - old_value_len;1368 self.consumed_space = self.consumed_space.saturating_sub(old_value_size) + value_size;
1353 } else {1369 } else {
1354 self.consumed_space -= old_value_len - value_len;1370 self.consumed_space += key_size + value_size;
1355 }1371 }
13561372
1357 Ok(old_value)1373 Ok(old_value)