1use alloc::collections::BTreeMap;
2use alloc::collections::btree_map::Entry;
3use alloc::vec::Vec;
4
5use super::{
6 AccountDeltaError,
7 ByteReader,
8 ByteWriter,
9 Deserializable,
10 DeserializationError,
11 Serializable,
12 Word,
13};
14use crate::account::{
15 StorageMap,
16 StorageMapKey,
17 StorageSlotContent,
18 StorageSlotName,
19 StorageSlotType,
20};
21use crate::{EMPTY_WORD, Felt, LexicographicWord, ZERO};
22
23#[derive(Clone, Debug, PartialEq, Eq)]
30pub struct AccountStorageDelta {
31 deltas: BTreeMap<StorageSlotName, StorageSlotDelta>,
33}
34
35impl AccountStorageDelta {
36 pub fn new() -> Self {
38 Self { deltas: BTreeMap::new() }
39 }
40
41 pub fn from_raw(deltas: BTreeMap<StorageSlotName, StorageSlotDelta>) -> Self {
43 Self { deltas }
44 }
45
46 pub fn get(&self, slot_name: &StorageSlotName) -> Option<&StorageSlotDelta> {
48 self.deltas.get(slot_name)
49 }
50
51 pub(crate) fn slots(&self) -> impl Iterator<Item = (&StorageSlotName, &StorageSlotDelta)> {
53 self.deltas.iter()
54 }
55
56 pub fn values(&self) -> impl Iterator<Item = (&StorageSlotName, &Word)> {
58 self.deltas.iter().filter_map(|(slot_name, slot_delta)| match slot_delta {
59 StorageSlotDelta::Value(word) => Some((slot_name, word)),
60 StorageSlotDelta::Map(_) => None,
61 })
62 }
63
64 pub fn maps(&self) -> impl Iterator<Item = (&StorageSlotName, &StorageMapDelta)> {
66 self.deltas.iter().filter_map(|(slot_name, slot_delta)| match slot_delta {
67 StorageSlotDelta::Value(_) => None,
68 StorageSlotDelta::Map(map_delta) => Some((slot_name, map_delta)),
69 })
70 }
71
72 pub fn is_empty(&self) -> bool {
74 self.deltas.is_empty()
75 }
76
77 pub fn set_item(
87 &mut self,
88 slot_name: StorageSlotName,
89 new_slot_value: Word,
90 ) -> Result<(), AccountDeltaError> {
91 if !self.deltas.get(&slot_name).map(StorageSlotDelta::is_value).unwrap_or(true) {
92 return Err(AccountDeltaError::StorageSlotUsedAsDifferentTypes(slot_name));
93 }
94
95 self.deltas.insert(slot_name, StorageSlotDelta::Value(new_slot_value));
96
97 Ok(())
98 }
99
100 pub fn set_map_item(
110 &mut self,
111 slot_name: StorageSlotName,
112 key: StorageMapKey,
113 new_value: Word,
114 ) -> Result<(), AccountDeltaError> {
115 match self
116 .deltas
117 .entry(slot_name.clone())
118 .or_insert(StorageSlotDelta::Map(StorageMapDelta::default()))
119 {
120 StorageSlotDelta::Value(_) => {
121 return Err(AccountDeltaError::StorageSlotUsedAsDifferentTypes(slot_name));
122 },
123 StorageSlotDelta::Map(storage_map_delta) => {
124 storage_map_delta.insert(key, new_value);
125 },
126 };
127
128 Ok(())
129 }
130
131 pub fn insert_empty_map_delta(&mut self, slot_name: StorageSlotName) {
137 self.deltas.insert(slot_name, StorageSlotDelta::with_empty_map());
138 }
139
140 pub fn merge(&mut self, other: Self) -> Result<(), AccountDeltaError> {
142 for (slot_name, slot_delta) in other.deltas {
143 match self.deltas.entry(slot_name.clone()) {
144 Entry::Vacant(vacant_entry) => {
145 vacant_entry.insert(slot_delta);
146 },
147 Entry::Occupied(mut occupied_entry) => {
148 occupied_entry.get_mut().merge(slot_delta).ok_or_else(|| {
149 AccountDeltaError::StorageSlotUsedAsDifferentTypes(slot_name)
150 })?;
151 },
152 }
153 }
154
155 Ok(())
156 }
157
158 fn cleared_values(&self) -> impl Iterator<Item = &StorageSlotName> {
160 self.values().filter_map(
161 |(slot_name, slot_value)| {
162 if slot_value.is_empty() { Some(slot_name) } else { None }
163 },
164 )
165 }
166
167 fn updated_values(&self) -> impl Iterator<Item = (&StorageSlotName, &Word)> {
169 self.values().filter_map(|(slot_name, slot_value)| {
170 if !slot_value.is_empty() {
171 Some((slot_name, slot_value))
172 } else {
173 None
174 }
175 })
176 }
177
178 pub(super) fn append_delta_elements(&self, elements: &mut Vec<Felt>) {
181 const DOMAIN_VALUE: Felt = Felt::new(2);
182 const DOMAIN_MAP: Felt = Felt::new(3);
183
184 for (slot_name, slot_delta) in self.deltas.iter() {
185 let slot_id = slot_name.id();
186
187 match slot_delta {
188 StorageSlotDelta::Value(new_value) => {
189 elements.extend_from_slice(&[
190 DOMAIN_VALUE,
191 ZERO,
192 slot_id.suffix(),
193 slot_id.prefix(),
194 ]);
195 elements.extend_from_slice(new_value.as_elements());
196 },
197 StorageSlotDelta::Map(map_delta) => {
198 for (key, value) in map_delta.entries() {
199 elements.extend_from_slice(key.inner().as_elements());
200 elements.extend_from_slice(value.as_elements());
201 }
202
203 let num_changed_entries = Felt::try_from(map_delta.num_entries() as u64)
204 .expect(
205 "number of changed entries should not exceed max representable felt",
206 );
207
208 elements.extend_from_slice(&[
209 DOMAIN_MAP,
210 num_changed_entries,
211 slot_id.suffix(),
212 slot_id.prefix(),
213 ]);
214 elements.extend_from_slice(EMPTY_WORD.as_elements());
215 },
216 }
217 }
218 }
219
220 pub fn into_map(self) -> BTreeMap<StorageSlotName, StorageSlotDelta> {
222 self.deltas
223 }
224}
225
226impl Default for AccountStorageDelta {
227 fn default() -> Self {
228 Self::new()
229 }
230}
231
232impl Serializable for AccountStorageDelta {
233 fn write_into<W: ByteWriter>(&self, target: &mut W) {
234 let num_cleared_values = self.cleared_values().count();
235 let num_cleared_values =
236 u8::try_from(num_cleared_values).expect("number of slots should fit in u8");
237 let cleared_values = self.cleared_values();
238
239 let num_updated_values = self.updated_values().count();
240 let num_updated_values =
241 u8::try_from(num_updated_values).expect("number of slots should fit in u8");
242 let updated_values = self.updated_values();
243
244 let num_maps = self.maps().count();
245 let num_maps = u8::try_from(num_maps).expect("number of slots should fit in u8");
246 let maps = self.maps();
247
248 target.write_u8(num_cleared_values);
249 target.write_many(cleared_values);
250
251 target.write_u8(num_updated_values);
252 target.write_many(updated_values);
253
254 target.write_u8(num_maps);
255 target.write_many(maps);
256 }
257
258 fn get_size_hint(&self) -> usize {
259 let u8_size = 0u8.get_size_hint();
260
261 let mut storage_map_delta_size = 0;
262 for (slot_name, storage_map_delta) in self.maps() {
263 storage_map_delta_size += slot_name.get_size_hint() + storage_map_delta.get_size_hint();
266 }
267
268 u8_size * 3 +
270 self.cleared_values().fold(0, |acc, slot_name| acc + slot_name.get_size_hint()) +
272 self.updated_values().fold(0, |acc, (slot_name, slot_value)| {
274 acc + slot_name.get_size_hint() + slot_value.get_size_hint()
275 }) +
276 storage_map_delta_size
278 }
279}
280
281impl Deserializable for AccountStorageDelta {
282 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
283 let mut deltas = BTreeMap::new();
284
285 let num_cleared_values = source.read_u8()?;
286 for _ in 0..num_cleared_values {
287 let cleared_value: StorageSlotName = source.read()?;
288 deltas.insert(cleared_value, StorageSlotDelta::with_empty_value());
289 }
290
291 let num_updated_values = source.read_u8()?;
292 for _ in 0..num_updated_values {
293 let (updated_slot, updated_value) = source.read()?;
294 deltas.insert(updated_slot, StorageSlotDelta::Value(updated_value));
295 }
296
297 let num_maps = source.read_u8()? as usize;
298 for read_result in source.read_many_iter::<(StorageSlotName, StorageMapDelta)>(num_maps)? {
299 let (slot_name, map_delta) = read_result?;
300 deltas.insert(slot_name, StorageSlotDelta::Map(map_delta));
301 }
302
303 Ok(Self::from_raw(deltas))
304 }
305}
306
307#[derive(Debug, Clone, PartialEq, Eq)]
316pub enum StorageSlotDelta {
317 Value(Word),
318 Map(StorageMapDelta),
319}
320
321impl StorageSlotDelta {
322 const VALUE: u8 = 0;
327
328 const MAP: u8 = 1;
330
331 pub fn with_empty_value() -> Self {
336 Self::Value(Word::empty())
337 }
338
339 pub fn with_empty_map() -> Self {
341 Self::Map(StorageMapDelta::default())
342 }
343
344 pub fn slot_type(&self) -> StorageSlotType {
349 match self {
350 StorageSlotDelta::Value(_) => StorageSlotType::Value,
351 StorageSlotDelta::Map(_) => StorageSlotType::Map,
352 }
353 }
354
355 pub fn is_value(&self) -> bool {
357 matches!(self, Self::Value(_))
358 }
359
360 pub fn is_map(&self) -> bool {
362 matches!(self, Self::Map(_))
363 }
364
365 pub fn unwrap_value(self) -> Word {
375 match self {
376 StorageSlotDelta::Value(value) => value,
377 StorageSlotDelta::Map(_) => panic!("called unwrap_value on a map slot delta"),
378 }
379 }
380
381 pub fn unwrap_map(self) -> StorageMapDelta {
388 match self {
389 StorageSlotDelta::Value(_) => panic!("called unwrap_map on a value slot delta"),
390 StorageSlotDelta::Map(map_delta) => map_delta,
391 }
392 }
393
394 #[must_use]
401 fn merge(&mut self, other: Self) -> Option<()> {
402 match (self, other) {
403 (StorageSlotDelta::Value(current_value), StorageSlotDelta::Value(new_value)) => {
404 *current_value = new_value;
405 },
406 (StorageSlotDelta::Map(current_map_delta), StorageSlotDelta::Map(new_map_delta)) => {
407 current_map_delta.merge(new_map_delta);
408 },
409 (..) => {
410 return None;
411 },
412 }
413
414 Some(())
415 }
416}
417
418impl From<StorageSlotContent> for StorageSlotDelta {
419 fn from(content: StorageSlotContent) -> Self {
420 match content {
421 StorageSlotContent::Value(word) => StorageSlotDelta::Value(word),
422 StorageSlotContent::Map(storage_map) => {
423 StorageSlotDelta::Map(StorageMapDelta::from(storage_map))
424 },
425 }
426 }
427}
428
429impl Serializable for StorageSlotDelta {
430 fn write_into<W: ByteWriter>(&self, target: &mut W) {
431 match self {
432 StorageSlotDelta::Value(value) => {
433 target.write_u8(Self::VALUE);
434 target.write(value);
435 },
436 StorageSlotDelta::Map(storage_map_delta) => {
437 target.write_u8(Self::MAP);
438 target.write(storage_map_delta);
439 },
440 }
441 }
442}
443
444impl Deserializable for StorageSlotDelta {
445 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
446 match source.read_u8()? {
447 Self::VALUE => {
448 let value = source.read()?;
449 Ok(Self::Value(value))
450 },
451 Self::MAP => {
452 let map_delta = source.read()?;
453 Ok(Self::Map(map_delta))
454 },
455 other => Err(DeserializationError::InvalidValue(format!(
456 "unknown storage slot delta variant {other}"
457 ))),
458 }
459 }
460}
461
462#[derive(Clone, Debug, Default, PartialEq, Eq)]
473pub struct StorageMapDelta(BTreeMap<LexicographicWord<StorageMapKey>, Word>);
474
475impl StorageMapDelta {
476 pub fn new(map: BTreeMap<LexicographicWord<StorageMapKey>, Word>) -> Self {
478 Self(map)
479 }
480
481 pub fn num_entries(&self) -> usize {
483 self.0.len()
484 }
485
486 pub fn entries(&self) -> &BTreeMap<LexicographicWord<StorageMapKey>, Word> {
490 &self.0
491 }
492
493 pub fn insert(&mut self, key: StorageMapKey, value: Word) {
495 self.0.insert(LexicographicWord::new(key), value);
496 }
497
498 pub fn is_empty(&self) -> bool {
500 self.0.is_empty()
501 }
502
503 pub fn merge(&mut self, other: Self) {
505 self.0.extend(other.0);
507 }
508
509 pub fn as_map_mut(&mut self) -> &mut BTreeMap<LexicographicWord<StorageMapKey>, Word> {
511 &mut self.0
512 }
513
514 fn cleared_keys(&self) -> impl Iterator<Item = &StorageMapKey> + '_ {
516 self.0.iter().filter(|&(_, value)| value.is_empty()).map(|(key, _)| key.inner())
517 }
518
519 fn updated_entries(&self) -> impl Iterator<Item = (&StorageMapKey, &Word)> + '_ {
521 self.0.iter().filter_map(|(key, value)| {
522 if !value.is_empty() {
523 Some((key.inner(), value))
524 } else {
525 None
526 }
527 })
528 }
529}
530
531#[cfg(any(feature = "testing", test))]
532impl StorageMapDelta {
533 pub fn from_iters(
535 cleared_leaves: impl IntoIterator<Item = StorageMapKey>,
536 updated_leaves: impl IntoIterator<Item = (StorageMapKey, Word)>,
537 ) -> Self {
538 Self(BTreeMap::from_iter(
539 cleared_leaves
540 .into_iter()
541 .map(|key| (LexicographicWord::new(key), EMPTY_WORD))
542 .chain(
543 updated_leaves
544 .into_iter()
545 .map(|(key, value)| (LexicographicWord::new(key), value)),
546 ),
547 ))
548 }
549
550 pub fn into_map(self) -> BTreeMap<LexicographicWord<StorageMapKey>, Word> {
552 self.0
553 }
554}
555
556impl From<StorageMap> for StorageMapDelta {
558 fn from(map: StorageMap) -> Self {
559 StorageMapDelta::new(
560 map.into_entries()
561 .into_iter()
562 .map(|(key, value)| (LexicographicWord::new(key), value))
563 .collect(),
564 )
565 }
566}
567
568impl Serializable for StorageMapDelta {
569 fn write_into<W: ByteWriter>(&self, target: &mut W) {
570 let cleared: Vec<&StorageMapKey> = self.cleared_keys().collect();
571 let updated: Vec<(&StorageMapKey, &Word)> = self.updated_entries().collect();
572
573 target.write_usize(cleared.len());
574 target.write_many(cleared.iter());
575
576 target.write_usize(updated.len());
577 target.write_many(updated.iter());
578 }
579
580 fn get_size_hint(&self) -> usize {
581 let cleared_keys_count = self.cleared_keys().count();
582 let updated_entries_count = self.updated_entries().count();
583
584 cleared_keys_count.get_size_hint() +
586 cleared_keys_count * StorageMapKey::SERIALIZED_SIZE +
587
588 updated_entries_count.get_size_hint() +
590 updated_entries_count * (StorageMapKey::SERIALIZED_SIZE + Word::SERIALIZED_SIZE)
591 }
592}
593
594impl Deserializable for StorageMapDelta {
595 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
596 let mut map = BTreeMap::new();
597
598 let cleared_count = source.read_usize()?;
599 for _ in 0..cleared_count {
600 let cleared_key = source.read()?;
601 map.insert(LexicographicWord::new(cleared_key), EMPTY_WORD);
602 }
603
604 let updated_count = source.read_usize()?;
605 for _ in 0..updated_count {
606 let (updated_key, updated_value) = source.read()?;
607 map.insert(LexicographicWord::new(updated_key), updated_value);
608 }
609
610 Ok(Self::new(map))
611 }
612}
613
614#[cfg(test)]
618mod tests {
619 use anyhow::Context;
620 use assert_matches::assert_matches;
621
622 use super::{AccountStorageDelta, Deserializable, Serializable};
623 use crate::account::{StorageMapDelta, StorageMapKey, StorageSlotDelta, StorageSlotName};
624 use crate::errors::AccountDeltaError;
625 use crate::{ONE, Word};
626
627 #[test]
628 fn account_storage_delta_returns_err_on_slot_type_mismatch() {
629 let value_slot_name = StorageSlotName::mock(1);
630 let map_slot_name = StorageSlotName::mock(2);
631
632 let mut delta = AccountStorageDelta::from_iters(
633 [value_slot_name.clone()],
634 [],
635 [(map_slot_name.clone(), StorageMapDelta::default())],
636 );
637
638 let err = delta
639 .set_map_item(value_slot_name.clone(), StorageMapKey::empty(), Word::empty())
640 .unwrap_err();
641 assert_matches!(err, AccountDeltaError::StorageSlotUsedAsDifferentTypes(slot_name) => {
642 assert_eq!(value_slot_name, slot_name)
643 });
644
645 let err = delta.set_item(map_slot_name.clone(), Word::empty()).unwrap_err();
646 assert_matches!(err, AccountDeltaError::StorageSlotUsedAsDifferentTypes(slot_name) => {
647 assert_eq!(map_slot_name, slot_name)
648 });
649 }
650
651 #[test]
652 fn test_is_empty() {
653 let storage_delta = AccountStorageDelta::new();
654 assert!(storage_delta.is_empty());
655
656 let storage_delta = AccountStorageDelta::from_iters([StorageSlotName::mock(1)], [], []);
657 assert!(!storage_delta.is_empty());
658
659 let storage_delta = AccountStorageDelta::from_iters(
660 [],
661 [(StorageSlotName::mock(2), Word::from([ONE, ONE, ONE, ONE]))],
662 [],
663 );
664 assert!(!storage_delta.is_empty());
665
666 let storage_delta = AccountStorageDelta::from_iters(
667 [],
668 [],
669 [(StorageSlotName::mock(3), StorageMapDelta::default())],
670 );
671 assert!(!storage_delta.is_empty());
672 }
673
674 #[test]
675 fn test_serde_account_storage_delta() {
676 let storage_delta = AccountStorageDelta::new();
677 let serialized = storage_delta.to_bytes();
678 let deserialized = AccountStorageDelta::read_from_bytes(&serialized).unwrap();
679 assert_eq!(deserialized, storage_delta);
680 assert_eq!(storage_delta.get_size_hint(), serialized.len());
681
682 let storage_delta = AccountStorageDelta::from_iters([StorageSlotName::mock(1)], [], []);
683 let serialized = storage_delta.to_bytes();
684 let deserialized = AccountStorageDelta::read_from_bytes(&serialized).unwrap();
685 assert_eq!(deserialized, storage_delta);
686 assert_eq!(storage_delta.get_size_hint(), serialized.len());
687
688 let storage_delta = AccountStorageDelta::from_iters(
689 [],
690 [(StorageSlotName::mock(2), Word::from([ONE, ONE, ONE, ONE]))],
691 [],
692 );
693 let serialized = storage_delta.to_bytes();
694 let deserialized = AccountStorageDelta::read_from_bytes(&serialized).unwrap();
695 assert_eq!(deserialized, storage_delta);
696 assert_eq!(storage_delta.get_size_hint(), serialized.len());
697
698 let storage_delta = AccountStorageDelta::from_iters(
699 [],
700 [],
701 [(StorageSlotName::mock(3), StorageMapDelta::default())],
702 );
703 let serialized = storage_delta.to_bytes();
704 let deserialized = AccountStorageDelta::read_from_bytes(&serialized).unwrap();
705 assert_eq!(deserialized, storage_delta);
706 assert_eq!(storage_delta.get_size_hint(), serialized.len());
707 }
708
709 #[test]
710 fn test_serde_storage_map_delta() {
711 let storage_map_delta = StorageMapDelta::default();
712 let serialized = storage_map_delta.to_bytes();
713 let deserialized = StorageMapDelta::read_from_bytes(&serialized).unwrap();
714 assert_eq!(deserialized, storage_map_delta);
715
716 let storage_map_delta =
717 StorageMapDelta::from_iters([StorageMapKey::from_array([1, 1, 1, 1])], []);
718 let serialized = storage_map_delta.to_bytes();
719 let deserialized = StorageMapDelta::read_from_bytes(&serialized).unwrap();
720 assert_eq!(deserialized, storage_map_delta);
721
722 let storage_map_delta = StorageMapDelta::from_iters(
723 [],
724 [(StorageMapKey::empty(), Word::from([ONE, ONE, ONE, ONE]))],
725 );
726 let serialized = storage_map_delta.to_bytes();
727 let deserialized = StorageMapDelta::read_from_bytes(&serialized).unwrap();
728 assert_eq!(deserialized, storage_map_delta);
729 }
730
731 #[test]
732 fn test_serde_storage_slot_value_delta() {
733 let slot_delta = StorageSlotDelta::with_empty_value();
734 let serialized = slot_delta.to_bytes();
735 let deserialized = StorageSlotDelta::read_from_bytes(&serialized).unwrap();
736 assert_eq!(deserialized, slot_delta);
737
738 let slot_delta = StorageSlotDelta::Value(Word::from([1, 2, 3, 4u32]));
739 let serialized = slot_delta.to_bytes();
740 let deserialized = StorageSlotDelta::read_from_bytes(&serialized).unwrap();
741 assert_eq!(deserialized, slot_delta);
742 }
743
744 #[test]
745 fn test_serde_storage_slot_map_delta() {
746 let slot_delta = StorageSlotDelta::with_empty_map();
747 let serialized = slot_delta.to_bytes();
748 let deserialized = StorageSlotDelta::read_from_bytes(&serialized).unwrap();
749 assert_eq!(deserialized, slot_delta);
750
751 let map_delta = StorageMapDelta::from_iters(
752 [StorageMapKey::from_array([1, 2, 3, 4])],
753 [(StorageMapKey::from_array([5, 6, 7, 8]), Word::from([3, 4, 5, 6u32]))],
754 );
755 let slot_delta = StorageSlotDelta::Map(map_delta);
756 let serialized = slot_delta.to_bytes();
757 let deserialized = StorageSlotDelta::read_from_bytes(&serialized).unwrap();
758 assert_eq!(deserialized, slot_delta);
759 }
760
761 #[rstest::rstest]
762 #[case::some_some(Some(1), Some(2), Some(2))]
763 #[case::none_some(None, Some(2), Some(2))]
764 #[case::some_none(Some(1), None, None)]
765 #[test]
766 fn merge_items(
767 #[case] x: Option<u32>,
768 #[case] y: Option<u32>,
769 #[case] expected: Option<u32>,
770 ) -> anyhow::Result<()> {
771 fn create_delta(item: Option<u32>) -> AccountStorageDelta {
773 let slot_name = StorageSlotName::mock(123);
774 let item = item.map(|x| (slot_name.clone(), Word::from([x, 0, 0, 0])));
775
776 AccountStorageDelta::new()
777 .add_cleared_items(item.is_none().then_some(slot_name.clone()))
778 .add_updated_values(item)
779 }
780
781 let mut delta_x = create_delta(x);
782 let delta_y = create_delta(y);
783 let expected = create_delta(expected);
784
785 delta_x.merge(delta_y).context("failed to merge deltas")?;
786
787 assert_eq!(delta_x, expected);
788
789 Ok(())
790 }
791
792 #[rstest::rstest]
793 #[case::some_some(Some(1), Some(2), Some(2))]
794 #[case::none_some(None, Some(2), Some(2))]
795 #[case::some_none(Some(1), None, None)]
796 #[test]
797 fn merge_maps(#[case] x: Option<u32>, #[case] y: Option<u32>, #[case] expected: Option<u32>) {
798 fn create_delta(value: Option<u32>) -> StorageMapDelta {
799 let key = StorageMapKey::from_array([10, 0, 0, 0]);
800 match value {
801 Some(value) => {
802 StorageMapDelta::from_iters([], [(key, Word::from([value, 0, 0, 0]))])
803 },
804 None => StorageMapDelta::from_iters([key], []),
805 }
806 }
807
808 let mut delta_x = create_delta(x);
809 let delta_y = create_delta(y);
810 let expected = create_delta(expected);
811
812 delta_x.merge(delta_y);
813
814 assert_eq!(delta_x, expected);
815 }
816}