1use alloy::primitives::U256;
15
16use crate::{
17 error::{Result, TempoPrecompileError},
18 storage::{
19 Layout, LayoutCtx, Storable, StorableType, StorageOps,
20 packing::{
21 calc_element_offset, calc_element_slot, calc_packed_slot_count, extract_packed_value,
22 insert_packed_value, is_packable, zero_packed_value,
23 },
24 types::Slot,
25 },
26};
27
28impl<T: StorableType> StorableType for Vec<T> {
29 const LAYOUT: Layout = Layout::Slots(1);
31}
32
33impl<T> Storable<1> for Vec<T>
34where
35 T: Storable<1> + StorableType,
36{
37 fn load<S: StorageOps>(
38 storage: &mut S,
39 base_slot: U256,
40 ctx: crate::storage::types::LayoutCtx,
41 ) -> Result<Self> {
42 debug_assert_eq!(ctx, LayoutCtx::FULL, "Dynamic arrays cannot be packed");
43
44 let length_value = storage.sload(base_slot)?;
46 let length = length_value.to::<usize>();
47
48 if length == 0 {
49 return Ok(Self::new());
50 }
51
52 let data_start = calc_data_slot(base_slot);
54 if T::BYTES <= 16 {
55 load_packed_elements(storage, data_start, length, T::BYTES)
56 } else {
57 load_unpacked_elements(storage, data_start, length)
58 }
59 }
60
61 fn store<S: StorageOps>(
62 &self,
63 storage: &mut S,
64 base_slot: U256,
65 ctx: crate::storage::types::LayoutCtx,
66 ) -> Result<()> {
67 debug_assert_eq!(ctx, LayoutCtx::FULL, "Dynamic arrays cannot be packed");
68
69 storage.sstore(base_slot, U256::from(self.len()))?;
71
72 if self.is_empty() {
73 return Ok(());
74 }
75
76 let data_start = calc_data_slot(base_slot);
78 if T::BYTES <= 16 {
79 store_packed_elements(self, storage, data_start, T::BYTES)
80 } else {
81 store_unpacked_elements(self, storage, data_start)
82 }
83 }
84
85 fn delete<S: StorageOps>(storage: &mut S, base_slot: U256, ctx: LayoutCtx) -> Result<()> {
86 debug_assert_eq!(ctx, LayoutCtx::FULL, "Dynamic arrays cannot be packed");
87
88 let length_value = storage.sload(base_slot)?;
90 let length = length_value.to::<usize>();
91
92 storage.sstore(base_slot, U256::ZERO)?;
94
95 if length == 0 {
96 return Ok(());
97 }
98
99 let data_start = calc_data_slot(base_slot);
100 if T::BYTES <= 16 {
101 let slot_count = calc_packed_slot_count(length, T::BYTES);
103 for slot_idx in 0..slot_count {
104 storage.sstore(data_start + U256::from(slot_idx), U256::ZERO)?;
105 }
106 } else {
107 for elem_idx in 0..length {
109 let elem_slot = data_start + U256::from(elem_idx);
110 T::delete(storage, elem_slot, LayoutCtx::FULL)?;
111 }
112 }
113
114 Ok(())
115 }
116
117 fn to_evm_words(&self) -> Result<[U256; 1]> {
118 Ok([U256::from(self.len())])
120 }
121
122 fn from_evm_words(_words: [U256; 1]) -> Result<Self> {
123 Err(TempoPrecompileError::Fatal(
124 "Cannot reconstruct `Vec` from base slot alone. Use `load()` with storage access."
125 .into(),
126 ))
127 }
128}
129
130pub trait VecSlotExt<T>
135where
136 T: Storable<1> + StorableType,
137{
138 fn len<S: StorageOps>(&self, storage: &mut S) -> Result<usize>;
140
141 fn read_at<S: StorageOps>(&self, storage: &mut S, index: usize) -> Result<T>;
143
144 fn write_at<S: StorageOps>(&self, storage: &mut S, index: usize, value: T) -> Result<()>;
149
150 fn push<S: StorageOps>(&self, storage: &mut S, value: T) -> Result<()>;
154
155 fn pop<S: StorageOps>(&self, storage: &mut S) -> Result<Option<T>>;
160}
161
162impl<T> VecSlotExt<T> for Slot<Vec<T>>
163where
164 T: Storable<1> + StorableType,
165{
166 fn len<S: StorageOps>(&self, storage: &mut S) -> Result<usize> {
167 read_length(storage, self.slot())
168 }
169
170 fn read_at<S: StorageOps>(&self, storage: &mut S, index: usize) -> Result<T> {
171 vec_read_at(storage, self.slot(), index)
172 }
173
174 fn write_at<S: StorageOps>(&self, storage: &mut S, index: usize, value: T) -> Result<()> {
175 vec_write_at(storage, self.slot(), index, value)
176 }
177
178 fn push<S: StorageOps>(&self, storage: &mut S, value: T) -> Result<()> {
179 vec_push(storage, self.slot(), value)
180 }
181
182 fn pop<S: StorageOps>(&self, storage: &mut S) -> Result<Option<T>> {
183 vec_pop(storage, self.slot())
184 }
185}
186
187#[inline]
191pub(crate) fn calc_data_slot(base_slot: U256) -> U256 {
192 U256::from_be_bytes(alloy::primitives::keccak256(base_slot.to_be_bytes::<32>()).0)
193}
194
195fn load_packed_elements<T, S>(
199 storage: &mut S,
200 data_start: U256,
201 length: usize,
202 byte_count: usize,
203) -> Result<Vec<T>>
204where
205 T: Storable<1> + StorableType,
206 S: StorageOps,
207{
208 let elements_per_slot = 32 / byte_count;
209 let slot_count = calc_packed_slot_count(length, byte_count);
210
211 let mut result = Vec::with_capacity(length);
212 let mut current_offset = 0;
213
214 for slot_idx in 0..slot_count {
215 let slot_addr = data_start + U256::from(slot_idx);
216 let slot_value = storage.sload(slot_addr)?;
217
218 let elements_in_this_slot = if slot_idx == slot_count - 1 {
220 length - (slot_idx * elements_per_slot)
222 } else {
223 elements_per_slot
224 };
225
226 for _ in 0..elements_in_this_slot {
228 let elem = extract_packed_value::<1, T>(slot_value, current_offset, byte_count)?;
229 result.push(elem);
230
231 current_offset += byte_count;
233 if current_offset >= 32 {
234 current_offset = 0;
235 }
236 }
237
238 current_offset = 0;
240 }
241
242 Ok(result)
243}
244
245fn store_packed_elements<T, S>(
249 elements: &[T],
250 storage: &mut S,
251 data_start: U256,
252 byte_count: usize,
253) -> Result<()>
254where
255 T: Storable<1> + StorableType,
256 S: StorageOps,
257{
258 let elements_per_slot = 32 / byte_count;
259 let slot_count = calc_packed_slot_count(elements.len(), byte_count);
260
261 for slot_idx in 0..slot_count {
262 let slot_addr = data_start + U256::from(slot_idx);
263 let start_elem = slot_idx * elements_per_slot;
264 let end_elem = (start_elem + elements_per_slot).min(elements.len());
265
266 let slot_value = build_packed_slot(&elements[start_elem..end_elem], byte_count)?;
267 storage.sstore(slot_addr, slot_value)?;
268 }
269
270 Ok(())
271}
272
273fn build_packed_slot<T>(elements: &[T], byte_count: usize) -> Result<U256>
277where
278 T: Storable<1> + StorableType,
279{
280 let mut slot_value = U256::ZERO;
281 let mut current_offset = 0;
282
283 for elem in elements {
284 slot_value = insert_packed_value(slot_value, elem, current_offset, byte_count)?;
285 current_offset += byte_count;
286 }
287
288 Ok(slot_value)
289}
290
291fn load_unpacked_elements<T, S>(storage: &mut S, data_start: U256, length: usize) -> Result<Vec<T>>
296where
297 T: Storable<1>,
298 S: StorageOps,
299{
300 let mut result = Vec::with_capacity(length);
301 for index in 0..length {
302 let elem = read_single_unpacked_element(storage, data_start, index)?;
303 result.push(elem);
304 }
305 Ok(result)
306}
307
308fn store_unpacked_elements<T, S>(elements: &[T], storage: &mut S, data_start: U256) -> Result<()>
312where
313 T: Storable<1>,
314 S: StorageOps,
315{
316 for (elem_idx, elem) in elements.iter().enumerate() {
317 let elem_slot = data_start + U256::from(elem_idx);
318 elem.store(storage, elem_slot, crate::storage::types::LayoutCtx::FULL)?;
319 }
320
321 Ok(())
322}
323
324#[inline]
328pub(crate) fn read_length<S: StorageOps>(storage: &mut S, base_slot: U256) -> Result<usize> {
329 let length_value = storage.sload(base_slot)?;
330 Ok(length_value.to::<usize>())
331}
332
333pub(crate) fn read_single_packed_element<T, S>(
335 storage: &mut S,
336 data_start: U256,
337 index: usize,
338 byte_count: usize,
339) -> Result<T>
340where
341 T: Storable<1> + StorableType,
342 S: StorageOps,
343{
344 let slot_idx = calc_element_slot(index, byte_count);
345 let offset = calc_element_offset(index, byte_count);
346
347 let slot_addr = data_start + U256::from(slot_idx);
348 let slot_value = storage.sload(slot_addr)?;
349
350 extract_packed_value::<1, T>(slot_value, offset, byte_count)
351}
352
353pub(crate) fn write_single_packed_element<T, S>(
355 storage: &mut S,
356 data_start: U256,
357 index: usize,
358 byte_count: usize,
359 value: T,
360) -> Result<()>
361where
362 T: Storable<1> + StorableType,
363 S: StorageOps,
364{
365 let offset = calc_element_offset(index, byte_count);
366 modify_packed_element(storage, data_start, index, byte_count, |slot_value| {
367 insert_packed_value(slot_value, &value, offset, byte_count)
368 })
369}
370
371fn zero_single_packed_element<S: StorageOps>(
373 storage: &mut S,
374 data_start: U256,
375 index: usize,
376 byte_count: usize,
377) -> Result<()> {
378 let offset = calc_element_offset(index, byte_count);
379 modify_packed_element(storage, data_start, index, byte_count, |slot_value| {
380 zero_packed_value(slot_value, offset, byte_count)
381 })
382}
383
384fn modify_packed_element<S, F>(
386 storage: &mut S,
387 data_start: U256,
388 index: usize,
389 byte_count: usize,
390 modify_fn: F,
391) -> Result<()>
392where
393 S: StorageOps,
394 F: FnOnce(U256) -> Result<U256>,
395{
396 let slot_idx = calc_element_slot(index, byte_count);
397 let slot_addr = data_start + U256::from(slot_idx);
398 let slot_value = storage.sload(slot_addr)?;
399 let new_slot_value = modify_fn(slot_value)?;
400 storage.sstore(slot_addr, new_slot_value)?;
401 Ok(())
402}
403
404pub(crate) fn read_single_unpacked_element<T, S>(
406 storage: &mut S,
407 data_start: U256,
408 index: usize,
409) -> Result<T>
410where
411 T: Storable<1>,
412 S: StorageOps,
413{
414 let elem_slot = data_start + U256::from(index);
415 T::load(storage, elem_slot, crate::storage::types::LayoutCtx::FULL)
416}
417
418pub(crate) fn write_single_unpacked_element<T, S>(
420 storage: &mut S,
421 data_start: U256,
422 index: usize,
423 value: T,
424) -> Result<()>
425where
426 T: Storable<1>,
427 S: StorageOps,
428{
429 let elem_slot = data_start + U256::from(index);
430 value.store(storage, elem_slot, crate::storage::types::LayoutCtx::FULL)
431}
432
433fn zero_single_unpacked_element<S: StorageOps>(
435 storage: &mut S,
436 data_start: U256,
437 index: usize,
438) -> Result<()> {
439 let elem_slot = data_start + U256::from(index);
440 storage.sstore(elem_slot, U256::ZERO)
441}
442
443fn vec_read_at<S, T>(storage: &mut S, base_slot: U256, index: usize) -> Result<T>
447where
448 S: StorageOps,
449 T: Storable<1> + StorableType,
450{
451 let byte_count = T::BYTES;
452 let data_start = calc_data_slot(base_slot);
453
454 if is_packable(byte_count) {
455 read_single_packed_element(storage, data_start, index, byte_count)
456 } else {
457 read_single_unpacked_element(storage, data_start, index)
458 }
459}
460
461fn vec_write_at<S, T>(storage: &mut S, base_slot: U256, index: usize, value: T) -> Result<()>
466where
467 S: StorageOps,
468 T: Storable<1> + StorableType,
469{
470 let byte_count = T::BYTES;
471 let data_start = calc_data_slot(base_slot);
472 let length = read_length(storage, base_slot)?;
473
474 if is_packable(byte_count) {
476 write_single_packed_element(storage, data_start, index, byte_count, value)?;
477 } else {
478 write_single_unpacked_element(storage, data_start, index, value)?;
479 }
480
481 if index >= length {
483 storage.sstore(base_slot, U256::from(index + 1))?;
484 }
485
486 Ok(())
487}
488
489fn vec_push<S, T>(storage: &mut S, base_slot: U256, value: T) -> Result<()>
493where
494 S: StorageOps,
495 T: Storable<1> + StorableType,
496{
497 let byte_count = T::BYTES;
498 let data_start = calc_data_slot(base_slot);
499 let length = read_length(storage, base_slot)?;
500
501 if is_packable(byte_count) {
503 write_single_packed_element(storage, data_start, length, byte_count, value)?;
504 } else {
505 write_single_unpacked_element(storage, data_start, length, value)?;
506 }
507
508 storage.sstore(base_slot, U256::from(length + 1))
510}
511
512fn vec_pop<S, T>(storage: &mut S, base_slot: U256) -> Result<Option<T>>
517where
518 S: StorageOps,
519 T: Storable<1> + StorableType,
520{
521 let byte_count = T::BYTES;
522 let data_start = calc_data_slot(base_slot);
523
524 let length = read_length(storage, base_slot)?;
526 if length == 0 {
527 return Ok(None);
528 }
529 let last_index = length - 1;
530
531 let element = if is_packable(byte_count) {
533 read_single_packed_element(storage, data_start, last_index, byte_count)?
534 } else {
535 read_single_unpacked_element(storage, data_start, last_index)?
536 };
537
538 if is_packable(byte_count) {
540 zero_single_packed_element(storage, data_start, last_index, byte_count)?;
541 } else {
542 zero_single_unpacked_element(storage, data_start, last_index)?;
543 }
544
545 storage.sstore(base_slot, U256::from(last_index))?;
547
548 Ok(Some(element))
549}
550
551#[cfg(test)]
552mod tests {
553 use super::*;
554 use crate::storage::{
555 PrecompileStorageProvider, StorageOps, hashmap::HashMapStorageProvider,
556 packing::gen_slot_from,
557 };
558 use alloy::primitives::Address;
559 use proptest::prelude::*;
560 use tempo_precompiles_macros::Storable;
561
562 struct TestContract {
566 address: Address,
567 storage: HashMapStorageProvider,
568 }
569
570 impl StorageOps for TestContract {
571 fn sstore(&mut self, slot: U256, value: U256) -> Result<()> {
572 self.storage.sstore(self.address, slot, value)
573 }
574
575 fn sload(&mut self, slot: U256) -> Result<U256> {
576 self.storage.sload(self.address, slot)
577 }
578 }
579
580 fn setup_test_contract() -> TestContract {
582 TestContract {
583 address: Address::random(),
584 storage: HashMapStorageProvider::new(1),
585 }
586 }
587
588 fn verify_packed_element<T>(
590 contract: &mut TestContract,
591 slot_addr: U256,
592 expected: T,
593 offset: usize,
594 byte_count: usize,
595 elem_name: &str,
596 ) where
597 T: Storable<1> + StorableType + PartialEq + std::fmt::Debug,
598 {
599 let slot_value = contract.sload(slot_addr).unwrap();
600 let actual = extract_packed_value::<1, T>(slot_value, offset, byte_count).unwrap();
601 assert_eq!(
602 actual, expected,
603 "{elem_name} at offset {offset} in slot {slot_addr:?} mismatch"
604 );
605 }
606
607 fn arb_safe_slot() -> impl Strategy<Value = U256> {
609 any::<[u64; 4]>().prop_map(|limbs| {
610 U256::from_limbs(limbs) % (U256::MAX - U256::from(10000))
612 })
613 }
614
615 #[derive(Debug, Clone, PartialEq, Eq, Storable)]
617 struct TestStruct {
618 a: u128, b: u128, }
621
622 #[test]
623 fn test_vec_empty() {
624 let mut contract = setup_test_contract();
625 let base_slot = U256::from(400);
626
627 let data: Vec<u8> = vec![];
628 data.store(&mut contract, base_slot, LayoutCtx::FULL)
629 .unwrap();
630
631 let loaded: Vec<u8> = Storable::load(&mut contract, base_slot, LayoutCtx::FULL).unwrap();
632 assert_eq!(loaded, data, "Empty vec roundtrip failed");
633 assert!(loaded.is_empty(), "Loaded vec should be empty");
634 }
635
636 #[test]
637 fn test_vec_nested() {
638 let mut contract = setup_test_contract();
639 let base_slot = U256::from(800);
640
641 let data = vec![vec![1u8, 2, 3], vec![4, 5], vec![6, 7, 8, 9]];
643 data.store(&mut contract, base_slot, LayoutCtx::FULL)
644 .unwrap();
645
646 let loaded: Vec<Vec<u8>> =
647 Storable::load(&mut contract, base_slot, LayoutCtx::FULL).unwrap();
648 assert_eq!(loaded, data, "Nested Vec<Vec<u8>> roundtrip failed");
649 }
650
651 #[test]
652 fn test_vec_bool_packing() {
653 let mut contract = setup_test_contract();
654 let base_slot = U256::from(900);
655
656 let data_exact: Vec<bool> = (0..32).map(|i| i % 2 == 0).collect();
658 data_exact
659 .store(&mut contract, base_slot, LayoutCtx::FULL)
660 .unwrap();
661
662 let length_value = contract.sload(base_slot).unwrap();
664 assert_eq!(length_value, U256::from(32), "Length not stored correctly");
665
666 let loaded: Vec<bool> = Storable::load(&mut contract, base_slot, LayoutCtx::FULL).unwrap();
667 assert_eq!(
668 loaded, data_exact,
669 "Vec<bool> with 32 elements failed roundtrip"
670 );
671
672 let data_overflow: Vec<bool> = (0..35).map(|i| i % 3 == 0).collect();
674 data_overflow
675 .store(&mut contract, base_slot, LayoutCtx::FULL)
676 .unwrap();
677
678 let loaded: Vec<bool> = Storable::load(&mut contract, base_slot, LayoutCtx::FULL).unwrap();
679 assert_eq!(
680 loaded, data_overflow,
681 "Vec<bool> with 35 elements failed roundtrip"
682 );
683 }
684
685 #[test]
688 fn test_vec_u8_explicit_slot_packing() {
689 let mut contract = setup_test_contract();
690 let base_slot = U256::from(2000);
691
692 let data = vec![10u8, 20, 30, 40, 50];
694 data.store(&mut contract, base_slot, LayoutCtx::FULL)
695 .unwrap();
696
697 let length_value = contract.sload(base_slot).unwrap();
699 assert_eq!(length_value, U256::from(5), "Length not stored correctly");
700
701 let data_start = calc_data_slot(base_slot);
702 let slot_value = contract.sload(data_start).unwrap();
703
704 let expected = gen_slot_from(&[
706 "0x32", "0x28", "0x1e", "0x14", "0x0a", ]);
712 assert_eq!(
713 slot_value, expected,
714 "Slot should match Solidity byte layout"
715 );
716
717 let byte_count = u8::BYTES;
719 verify_packed_element(&mut contract, data_start, 10u8, 0, byte_count, "elem[0]");
720 verify_packed_element(&mut contract, data_start, 20u8, 1, byte_count, "elem[1]");
721 verify_packed_element(&mut contract, data_start, 30u8, 2, byte_count, "elem[2]");
722 verify_packed_element(&mut contract, data_start, 40u8, 3, byte_count, "elem[3]");
723 verify_packed_element(&mut contract, data_start, 50u8, 4, byte_count, "elem[4]");
724 }
725
726 #[test]
727 fn test_vec_u16_slot_boundary() {
728 let mut contract = setup_test_contract();
729 let base_slot = U256::from(2100);
730
731 let data_exact: Vec<u16> = (0..16).map(|i| i * 100).collect();
733 data_exact
734 .store(&mut contract, base_slot, LayoutCtx::FULL)
735 .unwrap();
736
737 let data_start = calc_data_slot(base_slot);
738 let slot0_value = contract.sload(data_start).unwrap();
739
740 let expected_slot0 = gen_slot_from(&[
741 "0x05dc", "0x0578", "0x0514", "0x04b0", "0x044c", "0x03e8", "0x0384", "0x0320", "0x02bc", "0x0258", "0x01f4", "0x0190", "0x012c", "0x00c8", "0x0064", "0x0000", ]);
758 assert_eq!(
759 slot0_value, expected_slot0,
760 "Slot 0 should match Solidity byte layout"
761 );
762
763 let byte_count = u16::BYTES;
765 for (i, &expected) in data_exact.iter().enumerate() {
766 verify_packed_element(
767 &mut contract,
768 data_start,
769 expected,
770 i * byte_count,
771 byte_count,
772 &format!("elem[{i}]"),
773 );
774 }
775
776 let data_overflow: Vec<u16> = (0..17).map(|i| i * 100).collect();
778 data_overflow
779 .store(&mut contract, base_slot, LayoutCtx::FULL)
780 .unwrap();
781
782 let slot0_value = contract.sload(data_start).unwrap();
784 assert_eq!(
785 slot0_value, expected_slot0,
786 "Slot 0 should still match after overflow"
787 );
788
789 let slot1_addr = data_start + U256::ONE;
791 let slot1_value = contract.sload(slot1_addr).unwrap();
792
793 let expected_slot1 = gen_slot_from(&[
794 "0x0640", ]);
796 assert_eq!(
797 slot1_value, expected_slot1,
798 "Slot 1 should match Solidity byte layout"
799 );
800
801 verify_packed_element(
803 &mut contract,
804 slot1_addr,
805 1600u16,
806 0,
807 byte_count,
808 "slot1_elem[0]",
809 );
810 }
811
812 #[test]
813 fn test_vec_u8_partial_slot_fill() {
814 let mut contract = setup_test_contract();
815 let base_slot = U256::from(2200);
816
817 let data: Vec<u8> = (0..35).map(|i| (i + 1) as u8).collect();
821 data.store(&mut contract, base_slot, LayoutCtx::FULL)
822 .unwrap();
823 let data_start = calc_data_slot(base_slot);
824 let slot0_value = contract.sload(data_start).unwrap();
825
826 let expected_slot0 = gen_slot_from(&[
827 "0x20", "0x1f", "0x1e", "0x1d", "0x1c", "0x1b", "0x1a", "0x19", "0x18", "0x17", "0x16", "0x15", "0x14", "0x13", "0x12", "0x11", "0x10", "0x0f", "0x0e", "0x0d", "0x0c", "0x0b", "0x0a", "0x09", "0x08", "0x07", "0x06", "0x05", "0x04", "0x03", "0x02", "0x01", ]);
860 assert_eq!(
861 slot0_value, expected_slot0,
862 "Slot 0 should match Solidity byte layout"
863 );
864
865 let slot1_addr = data_start + U256::ONE;
867 let slot1_value = contract.sload(slot1_addr).unwrap();
868
869 let expected_slot1 = gen_slot_from(&[
870 "0x23", "0x22", "0x21", ]);
874 assert_eq!(
875 slot1_value, expected_slot1,
876 "Slot 1 should match Solidity byte layout"
877 );
878
879 let byte_count = u8::BYTES;
881 verify_packed_element(
882 &mut contract,
883 slot1_addr,
884 33u8,
885 0,
886 byte_count,
887 "slot1_elem[0]",
888 );
889 verify_packed_element(
890 &mut contract,
891 slot1_addr,
892 34u8,
893 1,
894 byte_count,
895 "slot1_elem[1]",
896 );
897 verify_packed_element(
898 &mut contract,
899 slot1_addr,
900 35u8,
901 2,
902 byte_count,
903 "slot1_elem[2]",
904 );
905 }
906
907 #[test]
908 fn test_vec_u256_individual_slots() {
909 let mut contract = setup_test_contract();
910 let base_slot = U256::from(2300);
911
912 let data = vec![
914 U256::from(0x1111111111111111u64),
915 U256::from(0x2222222222222222u64),
916 U256::from(0x3333333333333333u64),
917 ];
918 data.store(&mut contract, base_slot, LayoutCtx::FULL)
919 .unwrap();
920
921 let data_start = calc_data_slot(base_slot);
922
923 for (i, &expected) in data.iter().enumerate() {
925 let slot_addr = data_start + U256::from(i);
926 let stored_value = contract.sload(slot_addr).unwrap();
927 assert_eq!(
928 stored_value, expected,
929 "U256 element {i} at slot {slot_addr:?} incorrect"
930 );
931 }
932
933 let slot3_addr = data_start + U256::from(3);
935 let slot3_value = contract.sload(slot3_addr).unwrap();
936 assert_eq!(slot3_value, U256::ZERO, "Slot 3 should be empty");
937 }
938
939 #[test]
940 fn test_vec_address_unpacked_slots() {
941 let mut contract = setup_test_contract();
942 let base_slot = U256::from(2400);
943
944 let data = vec![
946 Address::repeat_byte(0xAA),
947 Address::repeat_byte(0xBB),
948 Address::repeat_byte(0xCC),
949 ];
950 data.store(&mut contract, base_slot, LayoutCtx::FULL)
951 .unwrap();
952
953 let data_start = calc_data_slot(base_slot);
954
955 let slot0_value = contract.sload(data_start).unwrap();
957 let expected_slot0 = gen_slot_from(&["0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"]);
958 assert_eq!(
959 slot0_value, expected_slot0,
960 "Slot 0 should match Solidity byte layout"
961 );
962
963 let slot1_addr = data_start + U256::ONE;
965 let slot1_value = contract.sload(slot1_addr).unwrap();
966 let expected_slot1 = gen_slot_from(&["0xBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"]);
967 assert_eq!(
968 slot1_value, expected_slot1,
969 "Slot 1 should match Solidity byte layout"
970 );
971
972 let slot2_addr = data_start + U256::from(2);
974 let slot2_value = contract.sload(slot2_addr).unwrap();
975 let expected_slot2 = gen_slot_from(&["0xCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"]);
976 assert_eq!(
977 slot2_value, expected_slot2,
978 "Slot 2 should match Solidity byte layout"
979 );
980
981 for (i, &expected_addr) in data.iter().enumerate() {
983 let slot_addr = data_start + U256::from(i);
984 let stored_value = contract.sload(slot_addr).unwrap();
985 let expected_u256 = U256::from_be_slice(expected_addr.as_slice());
986 assert_eq!(
987 stored_value, expected_u256,
988 "Address element {i} should match"
989 );
990 }
991 }
992
993 #[test]
994 fn test_vec_struct_slot_allocation() {
995 let mut contract = setup_test_contract();
996 let base_slot = U256::from(2500);
997
998 let data = vec![
1001 TestStruct { a: 100, b: 1 },
1002 TestStruct { a: 200, b: 2 },
1003 TestStruct { a: 300, b: 3 },
1004 ];
1005 data.store(&mut contract, base_slot, LayoutCtx::FULL)
1006 .unwrap();
1007
1008 let data_start = calc_data_slot(base_slot);
1009
1010 let slot0_value = contract.sload(data_start).unwrap();
1014 let expected_slot0 = gen_slot_from(&[
1015 "0x00000000000000000000000000000001", "0x00000000000000000000000000000064", ]);
1018 assert_eq!(
1019 slot0_value, expected_slot0,
1020 "Slot 0 should match Solidity byte layout"
1021 );
1022
1023 let slot1_addr = data_start + U256::ONE;
1025 let slot1_value = contract.sload(slot1_addr).unwrap();
1026 let expected_slot1 = gen_slot_from(&[
1027 "0x00000000000000000000000000000002", "0x000000000000000000000000000000C8", ]);
1030 assert_eq!(
1031 slot1_value, expected_slot1,
1032 "Slot 1 should match Solidity byte layout"
1033 );
1034
1035 let slot2_addr = data_start + U256::from(2);
1037 let slot2_value = contract.sload(slot2_addr).unwrap();
1038 let expected_slot2 = gen_slot_from(&[
1039 "0x00000000000000000000000000000003", "0x0000000000000000000000000000012C", ]);
1042 assert_eq!(
1043 slot2_value, expected_slot2,
1044 "Slot 2 should match Solidity byte layout"
1045 );
1046
1047 let slot3_addr = data_start + U256::from(3);
1049 let slot3_value = contract.sload(slot3_addr).unwrap();
1050 assert_eq!(slot3_value, U256::ZERO, "Slot 3 should be empty");
1051
1052 for (i, expected_struct) in data.iter().enumerate() {
1054 let struct_slot = data_start + U256::from(i);
1055 let loaded_struct =
1056 TestStruct::load(&mut contract, struct_slot, LayoutCtx::FULL).unwrap();
1057 assert_eq!(
1058 loaded_struct, *expected_struct,
1059 "TestStruct at slot {i} should match"
1060 );
1061 }
1062 }
1063
1064 #[test]
1065 fn test_vec_small_struct_storage() {
1066 #[derive(Debug, Clone, PartialEq, Eq, Storable)]
1070 struct SmallStruct {
1071 flag1: bool, flag2: bool, value: u16, }
1075
1076 let mut contract = setup_test_contract();
1077 let base_slot = U256::from(2550);
1078
1079 let data = vec![
1082 SmallStruct {
1083 flag1: true,
1084 flag2: false,
1085 value: 100,
1086 },
1087 SmallStruct {
1088 flag1: false,
1089 flag2: true,
1090 value: 200,
1091 },
1092 SmallStruct {
1093 flag1: true,
1094 flag2: true,
1095 value: 300,
1096 },
1097 ];
1098 data.store(&mut contract, base_slot, LayoutCtx::FULL)
1099 .unwrap();
1100
1101 let length_value = contract.sload(base_slot).unwrap();
1103 assert_eq!(length_value, U256::from(3), "Length not stored correctly");
1104
1105 let data_start = calc_data_slot(base_slot);
1106
1107 let slot0_value = contract.sload(data_start).unwrap();
1109 let expected_slot0 = gen_slot_from(&[
1110 "0x0064", "0x00", "0x01", ]);
1114 assert_eq!(
1115 slot0_value, expected_slot0,
1116 "Slot 0 should match Solidity layout for struct[0]"
1117 );
1118
1119 let slot1_addr = data_start + U256::ONE;
1121 let slot1_value = contract.sload(slot1_addr).unwrap();
1122 let expected_slot1 = gen_slot_from(&[
1123 "0x00c8", "0x01", "0x00", ]);
1127 assert_eq!(
1128 slot1_value, expected_slot1,
1129 "Slot 1 should match Solidity layout for struct[1]"
1130 );
1131
1132 let slot2_addr = data_start + U256::from(2);
1134 let slot2_value = contract.sload(slot2_addr).unwrap();
1135 let expected_slot2 = gen_slot_from(&[
1136 "0x012c", "0x01", "0x01", ]);
1140 assert_eq!(
1141 slot2_value, expected_slot2,
1142 "Slot 2 should match Solidity layout for struct[2]"
1143 );
1144
1145 let loaded: Vec<SmallStruct> =
1147 Storable::load(&mut contract, base_slot, LayoutCtx::FULL).unwrap();
1148 assert_eq!(loaded, data, "Vec<SmallStruct> roundtrip failed");
1149 }
1150
1151 #[test]
1152 fn test_vec_length_slot_isolation() {
1153 let mut contract = setup_test_contract();
1154 let base_slot = U256::from(2600);
1155
1156 let data = vec![100u8, 200, 250];
1158 data.store(&mut contract, base_slot, LayoutCtx::FULL)
1159 .unwrap();
1160
1161 let length_value = contract.sload(base_slot).unwrap();
1163 assert_eq!(length_value, U256::from(3), "Length slot incorrect");
1164
1165 let data_start = calc_data_slot(base_slot);
1167 assert_ne!(
1168 data_start,
1169 base_slot + U256::ONE,
1170 "Data should not start immediately after base slot"
1171 );
1172
1173 let data_slot_value = contract.sload(data_start).unwrap();
1175
1176 let expected = gen_slot_from(&[
1177 "0xfa", "0xc8", "0x64", ]);
1181 assert_eq!(
1182 data_slot_value, expected,
1183 "Data slot should match Solidity byte layout"
1184 );
1185
1186 verify_packed_element(&mut contract, data_start, 100u8, 0, 1, "elem[0]");
1188 verify_packed_element(&mut contract, data_start, 200u8, 1, 1, "elem[1]");
1189 verify_packed_element(&mut contract, data_start, 250u8, 2, 1, "elem[2]");
1190 }
1191
1192 #[test]
1193 fn test_vec_overwrite_cleanup() {
1194 let mut contract = setup_test_contract();
1195 let base_slot = U256::from(2700);
1196
1197 let data_long = vec![1u8, 2, 3, 4, 5];
1199 data_long
1200 .store(&mut contract, base_slot, LayoutCtx::FULL)
1201 .unwrap();
1202
1203 let data_start = calc_data_slot(base_slot);
1204
1205 let slot0_before = contract.sload(data_start).unwrap();
1207 assert_ne!(slot0_before, U256::ZERO, "Initial data should be stored");
1208
1209 let data_short = vec![10u8, 20, 30];
1211 data_short
1212 .store(&mut contract, base_slot, LayoutCtx::FULL)
1213 .unwrap();
1214
1215 let length_value = contract.sload(base_slot).unwrap();
1217 assert_eq!(length_value, U256::from(3), "Length should be updated");
1218
1219 verify_packed_element(&mut contract, data_start, 10u8, 0, 1, "new_elem[0]");
1221 verify_packed_element(&mut contract, data_start, 20u8, 1, 1, "new_elem[1]");
1222 verify_packed_element(&mut contract, data_start, 30u8, 2, 1, "new_elem[2]");
1223
1224 let loaded: Vec<u8> = Storable::load(&mut contract, base_slot, LayoutCtx::FULL).unwrap();
1225 assert_eq!(loaded, data_short, "Loaded vec should match short version");
1226 assert_eq!(loaded.len(), 3, "Length should be 3");
1227
1228 Vec::<u8>::delete(&mut contract, base_slot, LayoutCtx::FULL).unwrap();
1230 data_short
1231 .store(&mut contract, base_slot, LayoutCtx::FULL)
1232 .unwrap();
1233
1234 let slot0_after_delete = contract.sload(data_start).unwrap();
1236
1237 let expected = gen_slot_from(&[
1238 "0x1e", "0x14", "0x0a", ]);
1242 assert_eq!(
1243 slot0_after_delete, expected,
1244 "Slot should match Solidity byte layout after delete+store"
1245 );
1246
1247 verify_packed_element(&mut contract, data_start, 10u8, 0, 1, "elem[0]");
1249 verify_packed_element(&mut contract, data_start, 20u8, 1, 1, "elem[1]");
1250 verify_packed_element(&mut contract, data_start, 30u8, 2, 1, "elem[2]");
1251 }
1252
1253 prop_compose! {
1279 fn arb_u8_vec(max_len: usize) (vec in prop::collection::vec(any::<u8>(), 0..=max_len)) -> Vec<u8> {
1280 vec
1281 }
1282 }
1283
1284 prop_compose! {
1285 fn arb_u16_vec(max_len: usize) (vec in prop::collection::vec(any::<u16>(), 0..=max_len)) -> Vec<u16> {
1286 vec
1287 }
1288 }
1289
1290 prop_compose! {
1291 fn arb_u32_vec(max_len: usize) (vec in prop::collection::vec(any::<u32>(), 0..=max_len)) -> Vec<u32> {
1292 vec
1293 }
1294 }
1295
1296 prop_compose! {
1297 fn arb_u64_vec(max_len: usize) (vec in prop::collection::vec(any::<u64>(), 0..=max_len)) -> Vec<u64> {
1298 vec
1299 }
1300 }
1301
1302 prop_compose! {
1303 fn arb_u128_vec(max_len: usize) (vec in prop::collection::vec(any::<u128>(), 0..=max_len)) -> Vec<u128> {
1304 vec
1305 }
1306 }
1307
1308 prop_compose! {
1309 fn arb_u256_vec(max_len: usize) (vec in prop::collection::vec(any::<u64>(), 0..=max_len)) -> Vec<U256> {
1310 vec.into_iter().map(U256::from).collect()
1311 }
1312 }
1313
1314 prop_compose! {
1315 fn arb_address_vec(max_len: usize) (vec in prop::collection::vec(any::<[u8; 20]>(), 0..=max_len)) -> Vec<Address> {
1316 vec.into_iter().map(Address::from).collect()
1317 }
1318 }
1319
1320 prop_compose! {
1321 fn arb_test_struct() (a in any::<u64>(), b in any::<u64>()) -> TestStruct {
1322 TestStruct {
1323 a: a as u128,
1324 b: b as u128,
1325 }
1326 }
1327 }
1328
1329 prop_compose! {
1330 fn arb_test_struct_vec(max_len: usize)
1331 (vec in prop::collection::vec(arb_test_struct(), 0..=max_len))
1332 -> Vec<TestStruct> {
1333 vec
1334 }
1335 }
1336
1337 proptest! {
1340 #![proptest_config(ProptestConfig::with_cases(500))]
1341 #[test]
1342 fn proptest_vec_u8_roundtrip(data in arb_u8_vec(100), base_slot in arb_safe_slot()) {
1343 let mut contract = setup_test_contract();
1344 let data_len = data.len();
1345
1346 data.store(&mut contract, base_slot, LayoutCtx::FULL)?;
1348 let loaded: Vec<u8> = Storable::load(&mut contract, base_slot, LayoutCtx::FULL)?;
1349 prop_assert_eq!(&loaded, &data, "Vec<u8> roundtrip failed");
1350
1351 Vec::<u8>::delete(&mut contract, base_slot, LayoutCtx::FULL)?;
1353 let after_delete: Vec<u8> = Storable::load(&mut contract, base_slot, LayoutCtx::FULL)?;
1354 prop_assert!(after_delete.is_empty(), "Vec not empty after delete");
1355
1356 if data_len > 0 {
1358 let data_start = calc_data_slot(base_slot);
1359 let byte_count = u8::BYTES;
1360 let slot_count = calc_packed_slot_count(data_len, byte_count);
1361
1362 for i in 0..slot_count {
1363 let slot_value = contract.sload(data_start + U256::from(i))?;
1364 prop_assert_eq!(slot_value, U256::ZERO, "Data slot {} not cleared", i);
1365 }
1366 }
1367
1368 let words = data.to_evm_words()?;
1370 let result = Vec::<u8>::from_evm_words(words);
1371 prop_assert!(result.is_err(), "Vec should not be reconstructable from base slot alone");
1372 }
1373
1374 #[test]
1375 fn proptest_vec_u16_roundtrip(data in arb_u16_vec(100), base_slot in arb_safe_slot()) {
1376 let mut contract = setup_test_contract();
1377 let data_len = data.len();
1378
1379 data.store(&mut contract, base_slot, LayoutCtx::FULL)?;
1381 let loaded: Vec<u16> = Storable::load(&mut contract, base_slot, LayoutCtx::FULL)?;
1382 prop_assert_eq!(&loaded, &data, "Vec<u16> roundtrip failed");
1383
1384 Vec::<u16>::delete(&mut contract, base_slot, LayoutCtx::FULL)?;
1386 let after_delete: Vec<u16> = Storable::load(&mut contract, base_slot, LayoutCtx::FULL)?;
1387 prop_assert!(after_delete.is_empty(), "Vec not empty after delete");
1388
1389 if data_len > 0 {
1391 let data_start = calc_data_slot(base_slot);
1392 let byte_count = u16::BYTES;
1393 let slot_count = calc_packed_slot_count(data_len, byte_count);
1394
1395 for i in 0..slot_count {
1396 let slot_value = contract.sload(data_start + U256::from(i))?;
1397 prop_assert_eq!(slot_value, U256::ZERO, "Data slot {} not cleared", i);
1398 }
1399 }
1400
1401 let words = data.to_evm_words()?;
1403 let result = Vec::<u16>::from_evm_words(words);
1404 prop_assert!(result.is_err(), "Vec should not be reconstructable from base slot alone");
1405 }
1406
1407 #[test]
1408 fn proptest_vec_u32_roundtrip(data in arb_u32_vec(100), base_slot in arb_safe_slot()) {
1409 let mut contract = setup_test_contract();
1410 let data_len = data.len();
1411
1412 data.store(&mut contract, base_slot, LayoutCtx::FULL)?;
1414 let loaded: Vec<u32> = Storable::load(&mut contract, base_slot, LayoutCtx::FULL)?;
1415 prop_assert_eq!(&loaded, &data, "Vec<u32> roundtrip failed");
1416
1417 Vec::<u32>::delete(&mut contract, base_slot, LayoutCtx::FULL)?;
1419 let after_delete: Vec<u32> = Storable::load(&mut contract, base_slot, LayoutCtx::FULL)?;
1420 prop_assert!(after_delete.is_empty(), "Vec not empty after delete");
1421
1422 if data_len > 0 {
1424 let data_start = calc_data_slot(base_slot);
1425 let byte_count = u32::BYTES;
1426 let slot_count = calc_packed_slot_count(data_len, byte_count);
1427
1428 for i in 0..slot_count {
1429 let slot_value = contract.sload(data_start + U256::from(i))?;
1430 prop_assert_eq!(slot_value, U256::ZERO, "Data slot {} not cleared", i);
1431 }
1432 }
1433 }
1434
1435 #[test]
1436 fn proptest_vec_u64_roundtrip(data in arb_u64_vec(100), base_slot in arb_safe_slot()) {
1437 let mut contract = setup_test_contract();
1438 let data_len = data.len();
1439
1440 data.store(&mut contract, base_slot, LayoutCtx::FULL)?;
1442 let loaded: Vec<u64> = Storable::load(&mut contract, base_slot, LayoutCtx::FULL)?;
1443 prop_assert_eq!(&loaded, &data, "Vec<u64> roundtrip failed");
1444
1445 Vec::<u64>::delete(&mut contract, base_slot, LayoutCtx::FULL)?;
1447 let after_delete: Vec<u64> = Storable::load(&mut contract, base_slot, LayoutCtx::FULL)?;
1448 prop_assert!(after_delete.is_empty(), "Vec not empty after delete");
1449
1450 if data_len > 0 {
1452 let data_start = calc_data_slot(base_slot);
1453 let byte_count = u64::BYTES;
1454 let slot_count = calc_packed_slot_count(data_len, byte_count);
1455
1456 for i in 0..slot_count {
1457 let slot_value = contract.sload(data_start + U256::from(i))?;
1458 prop_assert_eq!(slot_value, U256::ZERO, "Data slot {} not cleared", i);
1459 }
1460 }
1461 }
1462
1463 #[test]
1464 fn proptest_vec_u128_roundtrip(data in arb_u128_vec(50), base_slot in arb_safe_slot()) {
1465 let mut contract = setup_test_contract();
1466 let data_len = data.len();
1467
1468 data.store(&mut contract, base_slot, LayoutCtx::FULL)?;
1470 let loaded: Vec<u128> = Storable::load(&mut contract, base_slot, LayoutCtx::FULL)?;
1471 prop_assert_eq!(&loaded, &data, "Vec<u128> roundtrip failed");
1472
1473 Vec::<u128>::delete(&mut contract, base_slot, LayoutCtx::FULL)?;
1475 let after_delete: Vec<u128> = Storable::load(&mut contract, base_slot, LayoutCtx::FULL)?;
1476 prop_assert!(after_delete.is_empty(), "Vec not empty after delete");
1477
1478 if data_len > 0 {
1480 let data_start = calc_data_slot(base_slot);
1481 let byte_count = u128::BYTES;
1482 let slot_count = calc_packed_slot_count(data_len, byte_count);
1483
1484 for i in 0..slot_count {
1485 let slot_value = contract.sload(data_start + U256::from(i))?;
1486 prop_assert_eq!(slot_value, U256::ZERO, "Data slot {} not cleared", i);
1487 }
1488 }
1489 }
1490
1491 #[test]
1492 fn proptest_vec_u256_roundtrip(data in arb_u256_vec(50), base_slot in arb_safe_slot()) {
1493 let mut contract = setup_test_contract();
1494 let data_len = data.len();
1495
1496 data.store(&mut contract, base_slot, LayoutCtx::FULL)?;
1498 let loaded: Vec<U256> = Storable::load(&mut contract, base_slot, LayoutCtx::FULL)?;
1499 prop_assert_eq!(&loaded, &data, "Vec<U256> roundtrip failed");
1500
1501 Vec::<U256>::delete(&mut contract, base_slot, LayoutCtx::FULL)?;
1503 let after_delete: Vec<U256> = Storable::load(&mut contract, base_slot, LayoutCtx::FULL)?;
1504 prop_assert!(after_delete.is_empty(), "Vec not empty after delete");
1505
1506 if data_len > 0 {
1508 let data_start = calc_data_slot(base_slot);
1509
1510 for i in 0..data_len {
1511 let slot_value = contract.sload(data_start + U256::from(i))?;
1512 prop_assert_eq!(slot_value, U256::ZERO, "Data slot {} not cleared", i);
1513 }
1514 }
1515
1516 let words = data.to_evm_words()?;
1518 let result = Vec::<U256>::from_evm_words(words);
1519 prop_assert!(result.is_err(), "Vec should not be reconstructable from base slot alone");
1520 }
1521
1522 #[test]
1523 fn proptest_vec_address_roundtrip(data in arb_address_vec(50), base_slot in arb_safe_slot()) {
1524 let mut contract = setup_test_contract();
1525 let data_len = data.len();
1526
1527 data.store(&mut contract, base_slot, LayoutCtx::FULL)?;
1529 let loaded: Vec<Address> = Storable::load(&mut contract, base_slot, LayoutCtx::FULL)?;
1530 prop_assert_eq!(&loaded, &data, "Vec<Address> roundtrip failed");
1531
1532 Vec::<Address>::delete(&mut contract, base_slot, LayoutCtx::FULL)?;
1534 let after_delete: Vec<Address> = Storable::load(&mut contract, base_slot, LayoutCtx::FULL)?;
1535 prop_assert!(after_delete.is_empty(), "Vec not empty after delete");
1536
1537 if data_len > 0 {
1540 let data_start = calc_data_slot(base_slot);
1541
1542 for i in 0..data_len {
1543 let slot_value = contract.sload(data_start + U256::from(i))?;
1544 prop_assert_eq!(slot_value, U256::ZERO, "Data slot {} not cleared", i);
1545 }
1546 }
1547
1548 let words = data.to_evm_words()?;
1550 let result = Vec::<Address>::from_evm_words(words);
1551 prop_assert!(result.is_err(), "Vec should not be reconstructable from base slot alone");
1552 }
1553
1554 #[test]
1555 fn proptest_vec_delete(data in arb_u8_vec(100), base_slot in arb_safe_slot()) {
1556 let mut contract = setup_test_contract();
1557
1558 data.store(&mut contract, base_slot, LayoutCtx::FULL)?;
1560
1561 Vec::<u8>::delete(&mut contract, base_slot, LayoutCtx::FULL)?;
1563
1564 let loaded: Vec<u8> = Storable::load(&mut contract, base_slot, LayoutCtx::FULL)?;
1566 prop_assert!(loaded.is_empty(), "Vec not empty after delete");
1567
1568 if !data.is_empty() {
1570 let data_start = calc_data_slot(base_slot);
1571 let byte_count = u8::BYTES;
1572 let slot_count = calc_packed_slot_count(data.len(), byte_count);
1573
1574 for i in 0..slot_count {
1575 let slot_value = contract.sload(data_start + U256::from(i))?;
1576 prop_assert_eq!(slot_value, U256::ZERO, "Data slot {} not cleared", i);
1577 }
1578 }
1579 }
1580
1581 #[test]
1582 fn proptest_vec_struct_roundtrip(data in arb_test_struct_vec(50), base_slot in arb_safe_slot()) {
1583 let mut contract = setup_test_contract();
1584 let data_len = data.len();
1585
1586 data.store(&mut contract, base_slot, LayoutCtx::FULL)?;
1588 let loaded: Vec<TestStruct> = Storable::load(&mut contract, base_slot, LayoutCtx::FULL)?;
1589 prop_assert_eq!(&loaded, &data, "Vec<TestStruct> roundtrip failed");
1590
1591 Vec::<TestStruct>::delete(&mut contract, base_slot, LayoutCtx::FULL)?;
1593 let after_delete: Vec<TestStruct> = Storable::load(&mut contract, base_slot, LayoutCtx::FULL)?;
1594 prop_assert!(after_delete.is_empty(), "Vec not empty after delete");
1595
1596 if data_len > 0 {
1598 let data_start = calc_data_slot(base_slot);
1599
1600 for i in 0..data_len {
1601 let slot_value = contract.sload(data_start + U256::from(i))?;
1602 prop_assert_eq!(slot_value, U256::ZERO, "Data slot {} not cleared", i);
1603 }
1604 }
1605
1606 let words = data.to_evm_words()?;
1608 let result = Vec::<TestStruct>::from_evm_words(words);
1609 prop_assert!(result.is_err(), "Vec should not be reconstructable from base slot alone");
1610 }
1611 }
1612
1613 const TEST_VEC_SLOT_2: U256 = U256::from_limbs([5000, 0, 0, 0]);
1615
1616 #[test]
1619 fn test_vecext_push_and_read_at_u8() {
1620 let mut contract = setup_test_contract();
1621 let vec_slot = Slot::<Vec<u8>>::new(TEST_VEC_SLOT_2);
1622
1623 for i in 0..5 {
1625 vec_slot.push(&mut contract, i * 10).unwrap();
1626 }
1627
1628 for i in 0..5 {
1630 let value = vec_slot.read_at(&mut contract, i).unwrap();
1631 assert_eq!(value, i as u8 * 10, "Element {i} mismatch");
1632 }
1633
1634 let length = read_length(&mut contract, TEST_VEC_SLOT_2).unwrap();
1636 assert_eq!(length, 5, "Length should be 5");
1637 }
1638
1639 #[test]
1640 fn test_vecext_write_at_existing() {
1641 let mut contract = setup_test_contract();
1642 let vec_slot = Slot::<Vec<u8>>::new(TEST_VEC_SLOT_2);
1643
1644 vec_slot.push(&mut contract, 10).unwrap();
1646 vec_slot.push(&mut contract, 20).unwrap();
1647 vec_slot.push(&mut contract, 30).unwrap();
1648
1649 vec_slot.write_at(&mut contract, 1, 99).unwrap();
1651
1652 assert_eq!(vec_slot.read_at(&mut contract, 0).unwrap(), 10);
1654 assert_eq!(vec_slot.read_at(&mut contract, 1).unwrap(), 99);
1655 assert_eq!(vec_slot.read_at(&mut contract, 2).unwrap(), 30);
1656
1657 let length = read_length(&mut contract, TEST_VEC_SLOT_2).unwrap();
1659 assert_eq!(length, 3);
1660 }
1661
1662 #[test]
1663 fn test_vecext_write_at_auto_expand() {
1664 let mut contract = setup_test_contract();
1665 let vec_slot = Slot::<Vec<u8>>::new(TEST_VEC_SLOT_2);
1666
1667 vec_slot.write_at(&mut contract, 10, 42).unwrap();
1669
1670 let length = read_length(&mut contract, TEST_VEC_SLOT_2).unwrap();
1672 assert_eq!(length, 11);
1673
1674 assert_eq!(vec_slot.read_at(&mut contract, 10).unwrap(), 42);
1676
1677 for i in 0..10 {
1679 assert_eq!(
1680 vec_slot.read_at(&mut contract, i).unwrap(),
1681 0,
1682 "Intermediate element {i} should be 0"
1683 );
1684 }
1685 }
1686
1687 #[test]
1688 fn test_vecext_pop_u8() {
1689 let mut contract = setup_test_contract();
1690 let vec_slot = Slot::<Vec<u8>>::new(TEST_VEC_SLOT_2);
1691
1692 vec_slot.push(&mut contract, 10).unwrap();
1694 vec_slot.push(&mut contract, 20).unwrap();
1695 vec_slot.push(&mut contract, 30).unwrap();
1696
1697 assert_eq!(vec_slot.pop(&mut contract).unwrap(), Some(30));
1699 assert_eq!(vec_slot.pop(&mut contract).unwrap(), Some(20));
1700 assert_eq!(vec_slot.pop(&mut contract).unwrap(), Some(10));
1701 assert_eq!(vec_slot.pop(&mut contract).unwrap(), None);
1702
1703 let length = read_length(&mut contract, TEST_VEC_SLOT_2).unwrap();
1705 assert_eq!(length, 0);
1706 }
1707
1708 #[test]
1709 fn test_vecext_len() {
1710 let mut contract = setup_test_contract();
1711 let vec_slot = Slot::<Vec<u8>>::new(TEST_VEC_SLOT_2);
1712
1713 assert_eq!(vec_slot.len(&mut contract).unwrap(), 0);
1715
1716 vec_slot.push(&mut contract, 10).unwrap();
1718 assert_eq!(vec_slot.len(&mut contract).unwrap(), 1);
1719
1720 vec_slot.push(&mut contract, 20).unwrap();
1721 assert_eq!(vec_slot.len(&mut contract).unwrap(), 2);
1722
1723 vec_slot.push(&mut contract, 30).unwrap();
1724 assert_eq!(vec_slot.len(&mut contract).unwrap(), 3);
1725
1726 vec_slot.pop(&mut contract).unwrap();
1728 assert_eq!(vec_slot.len(&mut contract).unwrap(), 2);
1729
1730 vec_slot.pop(&mut contract).unwrap();
1731 assert_eq!(vec_slot.len(&mut contract).unwrap(), 1);
1732
1733 vec_slot.pop(&mut contract).unwrap();
1734 assert_eq!(vec_slot.len(&mut contract).unwrap(), 0);
1735 }
1736
1737 #[test]
1738 fn test_vecext_u8_packing_multiple_per_slot() {
1739 let mut contract = setup_test_contract();
1740 let vec_slot = Slot::<Vec<u8>>::new(TEST_VEC_SLOT_2);
1741
1742 for i in 0..33 {
1744 vec_slot.push(&mut contract, i as u8).unwrap();
1745 }
1746
1747 for i in 0..33 {
1749 assert_eq!(vec_slot.read_at(&mut contract, i).unwrap(), i as u8);
1750 }
1751
1752 vec_slot.write_at(&mut contract, 31, 255).unwrap();
1754 assert_eq!(vec_slot.read_at(&mut contract, 31).unwrap(), 255);
1755
1756 vec_slot.write_at(&mut contract, 32, 254).unwrap();
1758 assert_eq!(vec_slot.read_at(&mut contract, 32).unwrap(), 254);
1759 }
1760
1761 #[test]
1762 fn test_vecext_u16_packing() {
1763 let mut contract = setup_test_contract();
1764 let vec_slot = Slot::<Vec<u16>>::new(TEST_VEC_SLOT_2);
1765
1766 for i in 0..17 {
1769 vec_slot.push(&mut contract, (i * 100) as u16).unwrap();
1770 }
1771
1772 for i in 0..17 {
1774 assert_eq!(
1775 vec_slot.read_at(&mut contract, i).unwrap(),
1776 (i * 100) as u16
1777 );
1778 }
1779
1780 vec_slot.write_at(&mut contract, 15, 9999).unwrap();
1782 assert_eq!(vec_slot.read_at(&mut contract, 15).unwrap(), 9999);
1783 }
1784
1785 #[test]
1788 fn test_vecext_push_and_read_at_u256() {
1789 let mut contract = setup_test_contract();
1790 let vec_slot = Slot::<Vec<U256>>::new(TEST_VEC_SLOT_2);
1791
1792 vec_slot.push(&mut contract, U256::from(111)).unwrap();
1794 vec_slot.push(&mut contract, U256::from(222)).unwrap();
1795 vec_slot.push(&mut contract, U256::from(333)).unwrap();
1796
1797 assert_eq!(vec_slot.read_at(&mut contract, 0).unwrap(), U256::from(111));
1799 assert_eq!(vec_slot.read_at(&mut contract, 1).unwrap(), U256::from(222));
1800 assert_eq!(vec_slot.read_at(&mut contract, 2).unwrap(), U256::from(333));
1801 }
1802
1803 #[test]
1804 fn test_vecext_write_at_u256_auto_expand() {
1805 let mut contract = setup_test_contract();
1806 let vec_slot = Slot::<Vec<U256>>::new(TEST_VEC_SLOT_2);
1807
1808 vec_slot
1810 .write_at(&mut contract, 5, U256::from(999))
1811 .unwrap();
1812
1813 let length = read_length(&mut contract, TEST_VEC_SLOT_2).unwrap();
1815 assert_eq!(length, 6);
1816
1817 assert_eq!(vec_slot.read_at(&mut contract, 5).unwrap(), U256::from(999));
1819
1820 for i in 0..5 {
1822 assert_eq!(vec_slot.read_at(&mut contract, i).unwrap(), U256::ZERO);
1823 }
1824 }
1825
1826 #[test]
1827 fn test_vecext_pop_u256() {
1828 let mut contract = setup_test_contract();
1829 let vec_slot = Slot::<Vec<U256>>::new(TEST_VEC_SLOT_2);
1830
1831 vec_slot.push(&mut contract, U256::from(100)).unwrap();
1832 vec_slot.push(&mut contract, U256::from(200)).unwrap();
1833
1834 assert_eq!(vec_slot.pop(&mut contract).unwrap(), Some(U256::from(200)));
1835 assert_eq!(vec_slot.pop(&mut contract).unwrap(), Some(U256::from(100)));
1836 assert_eq!(vec_slot.pop(&mut contract).unwrap(), None);
1837 }
1838
1839 #[test]
1840 fn test_vecext_address_unpacked() {
1841 let mut contract = setup_test_contract();
1842 let vec_slot = Slot::<Vec<Address>>::new(TEST_VEC_SLOT_2);
1843
1844 let addr1 = Address::repeat_byte(0xAA);
1845 let addr2 = Address::repeat_byte(0xBB);
1846
1847 vec_slot.push(&mut contract, addr1).unwrap();
1848 vec_slot.push(&mut contract, addr2).unwrap();
1849
1850 assert_eq!(vec_slot.read_at(&mut contract, 0).unwrap(), addr1);
1851 assert_eq!(vec_slot.read_at(&mut contract, 1).unwrap(), addr2);
1852
1853 let addr3 = Address::repeat_byte(0xCC);
1855 vec_slot.write_at(&mut contract, 0, addr3).unwrap();
1856 assert_eq!(vec_slot.read_at(&mut contract, 0).unwrap(), addr3);
1857 }
1858
1859 proptest! {
1862 #![proptest_config(ProptestConfig::with_cases(100))]
1863
1864 #[test]
1865 fn proptest_vecext_push_pop_u8(data in arb_u8_vec(50)) {
1866 let mut contract = setup_test_contract();
1867 let vec_slot = Slot::<Vec<u8>>::new(TEST_VEC_SLOT_2);
1868
1869 for &val in &data {
1871 vec_slot.push(&mut contract, val)?;
1872 }
1873
1874 let length = read_length(&mut contract, TEST_VEC_SLOT_2)?;
1876 prop_assert_eq!(length, data.len());
1877
1878 let mut popped = Vec::new();
1880 while let Some(val) = vec_slot.pop(&mut contract)? {
1881 popped.push(val);
1882 }
1883
1884 popped.reverse();
1885 prop_assert_eq!(popped, data);
1886
1887 let final_length = read_length(&mut contract, TEST_VEC_SLOT_2)?;
1889 prop_assert_eq!(final_length, 0);
1890 }
1891
1892 #[test]
1893 fn proptest_vecext_read_write_at_u8(data in arb_u8_vec(30)) {
1894 let mut contract = setup_test_contract();
1895 let vec_slot = Slot::<Vec<u8>>::new(TEST_VEC_SLOT_2);
1896
1897 for &val in &data {
1899 vec_slot.push(&mut contract, val)?;
1900 }
1901
1902 for (i, &expected) in data.iter().enumerate() {
1904 let actual = vec_slot.read_at(&mut contract, i)?;
1905 prop_assert_eq!(actual, expected, "Mismatch at index {}", i);
1906 }
1907
1908 for (i, &val) in data.iter().enumerate() {
1910 let new_val = val.wrapping_add(1);
1911 vec_slot.write_at(&mut contract, i, new_val)?;
1912 }
1913
1914 for (i, &original) in data.iter().enumerate() {
1916 let actual = vec_slot.read_at(&mut contract, i)?;
1917 let expected = original.wrapping_add(1);
1918 prop_assert_eq!(actual, expected, "Update mismatch at index {}", i);
1919 }
1920 }
1921
1922 #[test]
1923 fn proptest_vecext_push_pop_u256(data in arb_u256_vec(20)) {
1924 let mut contract = setup_test_contract();
1925 let vec_slot = Slot::<Vec<U256>>::new(TEST_VEC_SLOT_2);
1926
1927 for &val in &data {
1929 vec_slot.push(&mut contract, val)?;
1930 }
1931
1932 let mut popped = Vec::new();
1934 while let Some(val) = vec_slot.pop(&mut contract)? {
1935 popped.push(val);
1936 }
1937
1938 popped.reverse();
1939 prop_assert_eq!(popped, data);
1940 }
1941
1942 #[test]
1943 fn proptest_vecext_auto_expand_writes(indices in prop::collection::vec(0usize..20, 1..10)) {
1944 let mut contract = setup_test_contract();
1945 let vec_slot = Slot::<Vec<u8>>::new(TEST_VEC_SLOT_2);
1946
1947 for &idx in &indices {
1949 vec_slot.write_at(&mut contract, idx, idx as u8)?;
1950 }
1951
1952 let max_idx = indices.iter().copied().max().unwrap_or(0);
1954
1955 let length = read_length(&mut contract, TEST_VEC_SLOT_2)?;
1957 prop_assert_eq!(length, max_idx + 1);
1958
1959 for &idx in &indices {
1961 let actual = vec_slot.read_at(&mut contract, idx)?;
1962 prop_assert_eq!(actual, idx as u8);
1963 }
1964 }
1965 }
1966}