1use crate::account_changes::AccountChanges;
4use alloc::vec::Vec;
5
6#[cfg(not(feature = "std"))]
7use once_cell::race::OnceBox as OnceLock;
8#[cfg(feature = "std")]
9use std::sync::OnceLock;
10
11pub type BlockAccessList = Vec<AccountChanges>;
13
14#[cfg(feature = "rlp")]
16pub fn compute_block_access_list_hash(bal: &[AccountChanges]) -> alloy_primitives::B256 {
17 compute_block_access_list_hash_with_buf(bal, &mut Vec::new())
18}
19
20#[cfg(feature = "rlp")]
25pub fn compute_block_access_list_hash_with_buf(
26 bal: &[AccountChanges],
27 buf: &mut Vec<u8>,
28) -> alloy_primitives::B256 {
29 buf.clear();
30 alloy_rlp::encode_list(bal, buf);
31 alloy_primitives::keccak256(buf)
32}
33
34pub fn total_bal_items(bal: &[AccountChanges]) -> u64 {
37 bal.iter()
38 .map(|account| 1 + account.storage_changes().len() + account.storage_reads().len())
39 .sum::<usize>() as u64
40}
41
42pub mod bal {
44 use super::OnceLock;
45 use crate::{
46 BlockAccessIndex, BlockAccessListGasError, BlockAccessListHashMismatch,
47 account_changes::AccountChanges, diff::BalDiff,
48 };
49 use alloc::vec::{IntoIter, Vec};
50 use alloy_primitives::{B256, Bytes, map::HashMap};
51 use core::{
52 ops::{Deref, Index},
53 slice::Iter,
54 };
55
56 #[derive(Clone, Debug, Default, PartialEq, Eq)]
62 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
63 #[cfg_attr(
64 feature = "rlp",
65 derive(alloy_rlp::RlpEncodableWrapper, alloy_rlp::RlpDecodableWrapper)
66 )]
67 #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
68 #[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
69 pub struct Bal(Vec<AccountChanges>);
70
71 impl From<Bal> for Vec<AccountChanges> {
72 #[inline]
73 fn from(this: Bal) -> Self {
74 this.0
75 }
76 }
77
78 impl From<Vec<AccountChanges>> for Bal {
79 #[inline]
80 fn from(list: Vec<AccountChanges>) -> Self {
81 Self(list)
82 }
83 }
84
85 #[cfg(feature = "rlp")]
86 impl alloy_primitives::Sealable for Bal {
87 fn hash_slow(&self) -> alloy_primitives::B256 {
88 self.compute_hash()
89 }
90 }
91
92 impl Deref for Bal {
93 type Target = [AccountChanges];
94
95 #[inline]
96 fn deref(&self) -> &Self::Target {
97 self.as_slice()
98 }
99 }
100
101 impl IntoIterator for Bal {
102 type Item = AccountChanges;
103 type IntoIter = IntoIter<AccountChanges>;
104
105 #[inline]
106 fn into_iter(self) -> Self::IntoIter {
107 self.0.into_iter()
108 }
109 }
110
111 impl<'a> IntoIterator for &'a Bal {
112 type Item = &'a AccountChanges;
113 type IntoIter = Iter<'a, AccountChanges>;
114
115 #[inline]
116 fn into_iter(self) -> Self::IntoIter {
117 self.iter()
118 }
119 }
120
121 impl FromIterator<AccountChanges> for Bal {
122 fn from_iter<I: IntoIterator<Item = AccountChanges>>(iter: I) -> Self {
123 Self(iter.into_iter().collect())
124 }
125 }
126
127 impl<I> Index<I> for Bal
128 where
129 I: core::slice::SliceIndex<[AccountChanges]>,
130 {
131 type Output = I::Output;
132
133 #[inline]
134 fn index(&self, index: I) -> &Self::Output {
135 &self.0[index]
136 }
137 }
138
139 impl Bal {
140 #[inline]
142 pub const fn new(account_changes: Vec<AccountChanges>) -> Self {
143 Self(account_changes)
144 }
145
146 #[inline]
148 pub fn push(&mut self, account_changes: AccountChanges) {
149 self.0.push(account_changes)
150 }
151
152 pub fn merge<I>(&mut self, incoming: I)
162 where
163 I: IntoIterator<Item = AccountChanges>,
164 {
165 let existing_accounts = core::mem::take(&mut self.0);
166 let mut merged_accounts = Vec::<AccountChanges>::with_capacity(existing_accounts.len());
167 let mut account_positions = HashMap::<_, usize>::with_capacity_and_hasher(
168 existing_accounts.len(),
169 Default::default(),
170 );
171
172 for account_changes in existing_accounts.into_iter().chain(incoming) {
173 if let Some(&idx) = account_positions.get(&account_changes.address) {
174 merged_accounts[idx].merge(account_changes);
175 } else {
176 account_positions.insert(account_changes.address, merged_accounts.len());
177 merged_accounts.push(account_changes);
178 }
179 }
180
181 self.0 = merged_accounts;
182 }
183
184 #[must_use = "the returned index replaces the caller's position after the inserted layer"]
225 pub fn insert_changes_at<I>(
226 &mut self,
227 block_access_index: BlockAccessIndex,
228 incoming: I,
229 ) -> BlockAccessIndex
230 where
231 I: IntoIterator<Item = AccountChanges>,
232 {
233 let mut inserted = Self::default();
234 inserted.merge(incoming.into_iter().map(|mut account| {
237 account.storage_changes.retain(|slot_changes| !slot_changes.is_empty());
238 account
239 }));
240 for account in &mut inserted.0 {
241 account.normalize();
242 account.collapse_changes_at(block_access_index);
243 }
244 inserted.0.retain(|account| !account.is_empty());
245 if inserted.is_empty() {
246 return block_access_index;
247 }
248
249 let inserts_layer = inserted.0.iter().any(has_indexed_changes);
252 if inserts_layer {
253 for account in &mut self.0 {
254 account.shift_indices_from(block_access_index);
255 }
256 }
257
258 self.merge(inserted);
259 self.sort();
260
261 if !inserts_layer {
262 return block_access_index;
263 }
264 let mut positioned_index = block_access_index;
265 positioned_index.saturating_increment();
266 positioned_index
267 }
268
269 #[inline]
271 pub const fn is_empty(&self) -> bool {
272 self.0.is_empty()
273 }
274
275 #[inline]
277 pub const fn len(&self) -> usize {
278 self.0.len()
279 }
280
281 #[inline]
283 pub fn iter(&self) -> Iter<'_, AccountChanges> {
284 self.0.iter()
285 }
286
287 #[inline]
289 pub const fn as_slice(&self) -> &[AccountChanges] {
290 self.0.as_slice()
291 }
292
293 #[inline]
295 pub const fn as_vec(&self) -> &Vec<AccountChanges> {
296 &self.0
297 }
298
299 pub fn diff(&self, other: &[AccountChanges]) -> BalDiff {
301 BalDiff::between(self.as_slice(), other)
302 }
303
304 #[inline]
306 pub fn into_inner(self) -> Vec<AccountChanges> {
307 self.0
308 }
309
310 pub fn sort(&mut self) {
329 self.0.sort_unstable_by_key(|account| account.address);
330
331 for account in &mut self.0 {
332 account.sort();
333 }
334 }
335
336 #[inline]
338 pub const fn account_count(&self) -> usize {
339 self.0.len()
340 }
341
342 pub fn total_storage_changes(&self) -> usize {
344 self.0.iter().map(|a| a.storage_changes.len()).sum()
345 }
346
347 pub fn total_storage_reads(&self) -> usize {
349 self.0.iter().map(|a| a.storage_reads.len()).sum()
350 }
351
352 pub fn total_slots(&self) -> usize {
354 self.0.iter().map(|a| a.storage_changes.len() + a.storage_reads.len()).sum()
355 }
356
357 pub fn total_balance_changes(&self) -> usize {
359 self.0.iter().map(|a| a.balance_changes.len()).sum()
360 }
361
362 pub fn total_nonce_changes(&self) -> usize {
364 self.0.iter().map(|a| a.nonce_changes.len()).sum()
365 }
366
367 pub fn total_code_changes(&self) -> usize {
369 self.0.iter().map(|a| a.code_changes.len()).sum()
370 }
371
372 pub fn change_counts(&self) -> BalChangeCounts {
374 let mut counts = BalChangeCounts::default();
375 for account in &self.0 {
376 counts.accounts += 1;
377 counts.storage += account.storage_changes.len();
378 counts.balance += account.balance_changes.len();
379 counts.nonce += account.nonce_changes.len();
380 counts.code += account.code_changes.len();
381 }
382 counts
383 }
384
385 pub fn total_bal_items(&self) -> u64 {
388 super::total_bal_items(&self.0)
389 }
390
391 pub fn validate_structure(
397 &self,
398 transaction_count: usize,
399 ) -> Result<(), crate::BlockAccessListValidationError> {
400 crate::validate_block_access_list(self.as_slice(), transaction_count)
401 }
402
403 pub fn validate_gas_limit(&self, gas_limit: u64) -> Result<(), BlockAccessListGasError> {
408 let items = self.total_bal_items();
409 if items > gas_limit / crate::constants::ITEM_COST as u64 {
410 return Err(BlockAccessListGasError::new(items, gas_limit));
411 }
412 Ok(())
413 }
414
415 #[cfg(feature = "rlp")]
417 pub fn compute_hash(&self) -> alloy_primitives::B256 {
418 self.compute_hash_with_buf(&mut Vec::new())
419 }
420
421 #[cfg(feature = "rlp")]
429 pub fn compute_hash_with_buf(&self, buf: &mut Vec<u8>) -> alloy_primitives::B256 {
430 if self.0.is_empty() {
431 return crate::constants::EMPTY_BLOCK_ACCESS_LIST_HASH;
432 }
433 super::compute_block_access_list_hash_with_buf(&self.0, buf)
434 }
435 }
436
437 const fn has_indexed_changes(account: &AccountChanges) -> bool {
439 let AccountChanges {
440 address: _,
441 storage_changes,
442 storage_reads: _,
443 balance_changes,
444 nonce_changes,
445 code_changes,
446 } = account;
447 !storage_changes.is_empty()
448 || !balance_changes.is_empty()
449 || !nonce_changes.is_empty()
450 || !code_changes.is_empty()
451 }
452
453 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
455 pub struct BalChangeCounts {
456 pub accounts: usize,
458 pub storage: usize,
460 pub balance: usize,
462 pub nonce: usize,
464 pub code: usize,
466 }
467
468 #[derive(Clone, Debug)]
470 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
471 #[cfg_attr(feature = "serde", serde(transparent))]
472 pub struct RawBal {
473 raw: Bytes,
475 #[cfg_attr(feature = "serde", serde(skip, default))]
477 hash: OnceLock<B256>,
478 }
479
480 impl PartialEq for RawBal {
481 #[inline]
482 fn eq(&self, other: &Self) -> bool {
483 self.raw == other.raw
484 }
485 }
486
487 impl Eq for RawBal {}
488
489 impl From<Bytes> for RawBal {
490 #[inline]
491 fn from(raw: Bytes) -> Self {
492 Self::new(raw)
493 }
494 }
495
496 impl RawBal {
497 #[inline]
499 pub const fn new(raw: Bytes) -> Self {
500 Self { raw, hash: OnceLock::new() }
501 }
502
503 #[inline]
508 pub fn new_unchecked(raw: Bytes, hash: B256) -> Self {
509 let this = Self::new(raw);
510 #[allow(clippy::useless_conversion)]
511 let _ = this.hash.get_or_init(|| hash.into());
512 this
513 }
514
515 #[inline]
517 pub const fn as_raw(&self) -> &Bytes {
518 &self.raw
519 }
520
521 #[inline]
523 pub fn into_raw(self) -> Bytes {
524 self.raw
525 }
526
527 #[inline]
529 pub fn into_parts(self) -> (Bytes, B256) {
530 let hash = self.hash();
531 (self.raw, hash)
532 }
533
534 #[inline]
536 pub fn ensure_hash(&self, expected: B256) -> Result<(), BlockAccessListHashMismatch> {
537 let computed = self.hash();
538 if computed == expected {
539 Ok(())
540 } else {
541 Err(BlockAccessListHashMismatch::new(computed, expected))
542 }
543 }
544
545 #[inline]
549 pub fn hash(&self) -> B256 {
550 #[allow(clippy::useless_conversion)]
551 *self.hash.get_or_init(|| alloy_primitives::keccak256(self.raw.as_ref()).into())
552 }
553 }
554
555 #[cfg(feature = "rlp")]
556 impl alloy_rlp::Encodable for RawBal {
557 #[inline]
558 fn encode(&self, out: &mut dyn alloy_rlp::BufMut) {
559 out.put_slice(&self.raw);
560 }
561
562 #[inline]
563 fn length(&self) -> usize {
564 self.raw.len()
565 }
566 }
567
568 #[cfg(feature = "rlp")]
569 impl alloy_rlp::Decodable for RawBal {
570 #[inline]
571 fn decode(buf: &mut &[u8]) -> Result<Self, alloy_rlp::Error> {
572 let original = *buf;
573 let header = alloy_rlp::Header::decode(buf)?;
574 let header_len = original.len() - buf.len();
575 let raw_len = header_len + header.payload_length;
576 let raw = Bytes::copy_from_slice(&original[..raw_len]);
577 *buf = &original[raw_len..];
578 Ok(Self::new(raw))
579 }
580 }
581
582 #[derive(Clone, Debug)]
587 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
588 pub struct DecodedBal<T = Bal> {
589 decoded: T,
591 raw: RawBal,
593 }
594
595 impl<T: PartialEq> PartialEq for DecodedBal<T> {
596 #[inline]
597 fn eq(&self, other: &Self) -> bool {
598 self.decoded == other.decoded && self.raw == other.raw
599 }
600 }
601
602 impl<T: Eq> Eq for DecodedBal<T> {}
603
604 impl<T> DecodedBal<T> {
605 #[inline]
607 pub const fn new(decoded: T, raw: Bytes) -> Self {
608 Self { decoded, raw: RawBal::new(raw) }
609 }
610
611 #[inline]
616 pub fn new_unchecked(decoded: T, raw: Bytes, hash: B256) -> Self {
617 Self { decoded, raw: RawBal::new_unchecked(raw, hash) }
618 }
619
620 #[inline]
622 pub const fn with_raw_bal(decoded: T, raw: RawBal) -> Self {
623 Self { decoded, raw }
624 }
625
626 #[inline]
628 pub const fn as_bal(&self) -> &T {
629 &self.decoded
630 }
631
632 #[inline]
634 pub const fn as_raw(&self) -> &Bytes {
635 self.raw.as_raw()
636 }
637
638 #[inline]
640 pub const fn as_raw_bal(&self) -> &RawBal {
641 &self.raw
642 }
643
644 #[inline]
646 pub fn split(self) -> (T, Bytes) {
647 (self.decoded, self.raw.into_raw())
648 }
649
650 #[inline]
652 pub fn split_raw_bal(self) -> (T, RawBal) {
653 (self.decoded, self.raw)
654 }
655
656 #[inline]
658 pub fn into_parts(self) -> (T, Bytes, B256) {
659 let hash = self.hash();
660 let (decoded, raw) = self.split();
661 (decoded, raw, hash)
662 }
663
664 #[inline]
669 pub fn ensure_hash(&self, expected: B256) -> Result<(), BlockAccessListHashMismatch> {
670 let computed = self.hash();
671 if computed == expected {
672 Ok(())
673 } else {
674 Err(BlockAccessListHashMismatch::new(computed, expected))
675 }
676 }
677
678 #[inline]
682 pub fn hash(&self) -> B256 {
683 self.raw.hash()
684 }
685
686 #[inline]
688 pub fn convert<U>(self) -> DecodedBal<U>
689 where
690 U: From<T>,
691 {
692 self.map(U::from)
693 }
694
695 #[inline]
697 pub fn try_convert<U>(self) -> Result<DecodedBal<U>, U::Error>
698 where
699 U: TryFrom<T>,
700 {
701 self.try_map(U::try_from)
702 }
703
704 #[inline]
706 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> DecodedBal<U> {
707 let Self { decoded, raw } = self;
708 DecodedBal { decoded: f(decoded), raw }
709 }
710
711 #[inline]
713 pub fn try_map<U, E>(self, f: impl FnOnce(T) -> Result<U, E>) -> Result<DecodedBal<U>, E> {
714 let Self { decoded, raw } = self;
715 Ok(DecodedBal { decoded: f(decoded)?, raw })
716 }
717 }
718
719 #[cfg(feature = "rlp")]
720 impl DecodedBal {
721 #[inline]
723 pub fn from_rlp_bytes(raw: Bytes) -> Result<Self, alloy_rlp::Error> {
724 Self::from_rlp_bytes_as(raw)
725 }
726
727 #[inline]
729 pub fn from_raw_bal(raw: RawBal) -> Result<Self, alloy_rlp::Error> {
730 Self::from_raw_bal_as(raw)
731 }
732
733 #[inline]
735 pub fn from_rlp_bytes_as<T>(raw: Bytes) -> Result<DecodedBal<T>, alloy_rlp::Error>
736 where
737 T: alloy_rlp::Decodable,
738 {
739 Self::from_raw_bal_as(RawBal::new(raw))
740 }
741
742 #[inline]
744 pub fn from_raw_bal_as<T>(raw: RawBal) -> Result<DecodedBal<T>, alloy_rlp::Error>
745 where
746 T: alloy_rlp::Decodable,
747 {
748 let mut slice = raw.as_raw().as_ref();
749 let decoded = T::decode(&mut slice)?;
750 if !slice.is_empty() {
751 return Err(alloy_rlp::Error::UnexpectedLength);
752 }
753 Ok(DecodedBal::with_raw_bal(decoded, raw))
754 }
755 }
756
757 #[cfg(feature = "rlp")]
758 impl<T> DecodedBal<T>
759 where
760 T: alloy_primitives::Sealable,
761 {
762 #[inline]
764 pub fn as_sealed_bal(&self) -> alloy_primitives::Sealed<&T> {
765 alloy_primitives::Sealable::seal_ref_unchecked(&self.decoded, self.hash())
766 }
767
768 #[inline]
770 pub fn into_sealed(self) -> alloy_primitives::Sealed<T> {
771 let seal = self.hash();
772 let (decoded, _) = self.split();
773 alloy_primitives::Sealable::seal_unchecked(decoded, seal)
774 }
775 }
776
777 #[cfg(feature = "rlp")]
778 impl<T> alloy_rlp::Decodable for DecodedBal<T>
779 where
780 T: alloy_rlp::Decodable,
781 {
782 #[inline]
783 fn decode(buf: &mut &[u8]) -> Result<Self, alloy_rlp::Error> {
784 let original = *buf;
785 let decoded = T::decode(buf)?;
786 let consumed = original.len() - buf.len();
787 let raw = Bytes::copy_from_slice(&original[..consumed]);
788 Ok(Self::new(decoded, raw))
789 }
790 }
791
792 #[cfg(feature = "rlp")]
793 impl<T> alloy_rlp::Encodable for DecodedBal<T> {
794 #[inline]
795 fn encode(&self, out: &mut dyn alloy_rlp::BufMut) {
796 alloy_rlp::Encodable::encode(&self.raw, out);
797 }
798
799 #[inline]
800 fn length(&self) -> usize {
801 alloy_rlp::Encodable::length(&self.raw)
802 }
803 }
804
805 #[derive(Clone, Debug, PartialEq, Eq)]
811 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
812 pub enum RawOrDecodedBal<T = Bal> {
813 Raw(RawBal),
815 Decoded(DecodedBal<T>),
817 }
818
819 impl<T> From<Bytes> for RawOrDecodedBal<T> {
820 #[inline]
821 fn from(raw: Bytes) -> Self {
822 Self::Raw(RawBal::new(raw))
823 }
824 }
825
826 impl<T> From<RawBal> for RawOrDecodedBal<T> {
827 #[inline]
828 fn from(raw: RawBal) -> Self {
829 Self::Raw(raw)
830 }
831 }
832
833 impl<T> From<DecodedBal<T>> for RawOrDecodedBal<T> {
834 #[inline]
835 fn from(decoded: DecodedBal<T>) -> Self {
836 Self::Decoded(decoded)
837 }
838 }
839
840 impl<T> RawOrDecodedBal<T> {
841 #[inline]
843 pub const fn raw(raw: Bytes) -> Self {
844 Self::Raw(RawBal::new(raw))
845 }
846
847 #[inline]
852 pub fn raw_unchecked(raw: Bytes, hash: B256) -> Self {
853 Self::Raw(RawBal::new_unchecked(raw, hash))
854 }
855
856 #[inline]
858 pub const fn raw_bal(raw: RawBal) -> Self {
859 Self::Raw(raw)
860 }
861
862 #[inline]
864 pub const fn decoded(decoded: DecodedBal<T>) -> Self {
865 Self::Decoded(decoded)
866 }
867
868 #[inline]
870 pub const fn is_raw(&self) -> bool {
871 matches!(self, Self::Raw(_))
872 }
873
874 #[inline]
876 pub const fn is_decoded(&self) -> bool {
877 matches!(self, Self::Decoded(_))
878 }
879
880 #[inline]
882 pub const fn as_raw(&self) -> &Bytes {
883 match self {
884 Self::Raw(raw) => raw.as_raw(),
885 Self::Decoded(decoded) => decoded.as_raw(),
886 }
887 }
888
889 #[inline]
891 pub const fn as_raw_bal(&self) -> &RawBal {
892 match self {
893 Self::Raw(raw) => raw,
894 Self::Decoded(decoded) => decoded.as_raw_bal(),
895 }
896 }
897
898 #[inline]
900 pub const fn as_decoded(&self) -> Option<&DecodedBal<T>> {
901 match self {
902 Self::Raw(_) => None,
903 Self::Decoded(decoded) => Some(decoded),
904 }
905 }
906
907 #[inline]
909 pub fn into_decoded(self) -> Option<DecodedBal<T>> {
910 match self {
911 Self::Raw(_) => None,
912 Self::Decoded(decoded) => Some(decoded),
913 }
914 }
915
916 #[inline]
918 pub const fn as_bal(&self) -> Option<&T> {
919 match self {
920 Self::Raw(_) => None,
921 Self::Decoded(decoded) => Some(decoded.as_bal()),
922 }
923 }
924
925 #[inline]
927 pub fn into_raw(self) -> Bytes {
928 match self {
929 Self::Raw(raw) => raw.into_raw(),
930 Self::Decoded(decoded) => decoded.split().1,
931 }
932 }
933
934 #[inline]
936 pub fn into_raw_bal(self) -> RawBal {
937 match self {
938 Self::Raw(raw) => raw,
939 Self::Decoded(decoded) => decoded.split_raw_bal().1,
940 }
941 }
942
943 #[inline]
945 pub fn split(self) -> (Option<T>, Bytes) {
946 match self {
947 Self::Raw(raw) => (None, raw.into_raw()),
948 Self::Decoded(decoded) => {
949 let (bal, raw) = decoded.split();
950 (Some(bal), raw)
951 }
952 }
953 }
954
955 #[inline]
957 pub fn split_raw_bal(self) -> (Option<T>, RawBal) {
958 match self {
959 Self::Raw(raw) => (None, raw),
960 Self::Decoded(decoded) => {
961 let (bal, raw) = decoded.split_raw_bal();
962 (Some(bal), raw)
963 }
964 }
965 }
966
967 #[inline]
969 pub fn ensure_hash(&self, expected: B256) -> Result<(), BlockAccessListHashMismatch> {
970 let computed = self.hash();
971 if computed == expected {
972 Ok(())
973 } else {
974 Err(BlockAccessListHashMismatch::new(computed, expected))
975 }
976 }
977
978 #[inline]
980 pub fn hash(&self) -> B256 {
981 match self {
982 Self::Raw(raw) => raw.hash(),
983 Self::Decoded(decoded) => decoded.hash(),
984 }
985 }
986
987 #[inline]
991 pub fn convert<U>(self) -> RawOrDecodedBal<U>
992 where
993 U: From<T>,
994 {
995 self.map(U::from)
996 }
997
998 #[inline]
1002 pub fn try_convert<U>(self) -> Result<RawOrDecodedBal<U>, U::Error>
1003 where
1004 U: TryFrom<T>,
1005 {
1006 self.try_map(U::try_from)
1007 }
1008
1009 #[inline]
1011 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> RawOrDecodedBal<U> {
1012 match self {
1013 Self::Raw(raw) => RawOrDecodedBal::Raw(raw),
1014 Self::Decoded(decoded) => RawOrDecodedBal::Decoded(decoded.map(f)),
1015 }
1016 }
1017
1018 #[inline]
1020 pub fn try_map<U, E>(
1021 self,
1022 f: impl FnOnce(T) -> Result<U, E>,
1023 ) -> Result<RawOrDecodedBal<U>, E> {
1024 match self {
1025 Self::Raw(raw) => Ok(RawOrDecodedBal::Raw(raw)),
1026 Self::Decoded(decoded) => decoded.try_map(f).map(RawOrDecodedBal::Decoded),
1027 }
1028 }
1029 }
1030
1031 #[cfg(feature = "rlp")]
1032 impl<T> RawOrDecodedBal<T>
1033 where
1034 T: alloy_rlp::Decodable,
1035 {
1036 #[inline]
1038 pub fn try_into_decoded(self) -> Result<DecodedBal<T>, alloy_rlp::Error> {
1039 match self {
1040 Self::Raw(raw) => DecodedBal::from_raw_bal_as(raw),
1041 Self::Decoded(decoded) => Ok(decoded),
1042 }
1043 }
1044 }
1045
1046 #[cfg(feature = "rlp")]
1047 impl<T> alloy_rlp::Encodable for RawOrDecodedBal<T> {
1048 #[inline]
1049 fn encode(&self, out: &mut dyn alloy_rlp::BufMut) {
1050 out.put_slice(self.as_raw());
1051 }
1052
1053 #[inline]
1054 fn length(&self) -> usize {
1055 self.as_raw().len()
1056 }
1057 }
1058
1059 #[cfg(feature = "rlp")]
1060 impl<T> alloy_rlp::Decodable for RawOrDecodedBal<T> {
1061 #[inline]
1062 fn decode(buf: &mut &[u8]) -> Result<Self, alloy_rlp::Error> {
1063 <RawBal as alloy_rlp::Decodable>::decode(buf).map(Self::Raw)
1064 }
1065 }
1066}
1067
1068#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, thiserror::Error)]
1070#[error(
1071 "block access list item cost exceeds gas limit: items={items}, max_items={max_items}, gas_limit={gas_limit}"
1072)]
1073pub struct BlockAccessListGasError {
1074 pub items: u64,
1076 pub max_items: u64,
1078 pub gas_limit: u64,
1080}
1081
1082impl BlockAccessListGasError {
1083 #[inline]
1085 pub const fn new(items: u64, gas_limit: u64) -> Self {
1086 Self { items, max_items: gas_limit / crate::constants::ITEM_COST as u64, gas_limit }
1087 }
1088}
1089
1090#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, thiserror::Error)]
1092#[error("block access list hash mismatch: computed={computed}, expected={expected}")]
1093pub struct BlockAccessListHashMismatch {
1094 pub computed: alloy_primitives::B256,
1096 pub expected: alloy_primitives::B256,
1098}
1099
1100impl BlockAccessListHashMismatch {
1101 #[inline]
1103 pub const fn new(computed: alloy_primitives::B256, expected: alloy_primitives::B256) -> Self {
1104 Self { computed, expected }
1105 }
1106}
1107
1108#[cfg(test)]
1109mod hash_tests {
1110 use super::bal::{Bal, DecodedBal, RawBal, RawOrDecodedBal};
1111 use crate::{
1112 AccountChanges, BalanceChange, BlockAccessIndex, CodeChange, NonceChange, SlotChanges,
1113 StorageChange, constants::ITEM_COST,
1114 };
1115 use alloc::vec::Vec;
1116 use alloy_primitives::{Address, B256, Bytes, U256};
1117
1118 #[test]
1119 fn decoded_bal_hash_uses_raw_bytes_without_rlp_feature() {
1120 let raw = Bytes::from_static(&[0xc0]);
1121 let decoded = DecodedBal::new(Bal::default(), raw.clone());
1122
1123 assert_eq!(decoded.hash(), alloy_primitives::keccak256(raw.as_ref()));
1124
1125 let (bal, split_raw, split_hash) = decoded.into_parts();
1126 assert!(bal.is_empty());
1127 assert_eq!(split_raw, raw);
1128 assert_eq!(split_hash, alloy_primitives::keccak256(raw.as_ref()));
1129 }
1130
1131 #[test]
1132 fn decoded_bal_map_preserves_raw_and_hash() {
1133 let raw = Bytes::from_static(&[0xc0]);
1134 let decoded = DecodedBal::new(Bal::default(), raw.clone());
1135 let hash = decoded.hash();
1136
1137 let mapped = decoded.map(|bal| bal.len());
1138
1139 assert_eq!(mapped.as_bal(), &0);
1140 assert_eq!(mapped.as_raw(), &raw);
1141 assert_eq!(mapped.hash(), hash);
1142 }
1143
1144 #[test]
1145 fn decoded_bal_try_map_converts_or_returns_error() {
1146 let raw = Bytes::from_static(&[0xc0]);
1147 let decoded = DecodedBal::new(Bal::default(), raw.clone());
1148
1149 let mapped = decoded.try_map(|bal| Ok::<_, core::convert::Infallible>(bal.len())).unwrap();
1150
1151 assert_eq!(mapped.as_bal(), &0);
1152 assert_eq!(mapped.as_raw(), &raw);
1153
1154 let decoded = DecodedBal::new(Bal::default(), raw);
1155 let err = decoded.try_map(|_| Err::<usize, _>("expected error")).unwrap_err();
1156
1157 assert_eq!(err, "expected error");
1158 }
1159
1160 #[test]
1161 fn bal_as_vec_returns_inner_vector_ref() {
1162 let bal = Bal::new(vec![AccountChanges::new(Address::from([0x11; 20]))]);
1163
1164 assert_eq!(bal.as_vec().len(), 1);
1165 assert_eq!(bal.as_vec().as_slice(), bal.as_slice());
1166 }
1167
1168 #[derive(Debug, PartialEq, Eq)]
1169 struct BalLen(usize);
1170
1171 impl From<Bal> for BalLen {
1172 fn from(value: Bal) -> Self {
1173 Self(value.len())
1174 }
1175 }
1176
1177 #[derive(Debug, PartialEq, Eq)]
1178 struct NonEmptyBal(Bal);
1179
1180 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
1181 struct EmptyBal;
1182
1183 impl TryFrom<Bal> for NonEmptyBal {
1184 type Error = EmptyBal;
1185
1186 fn try_from(value: Bal) -> Result<Self, Self::Error> {
1187 if value.is_empty() { Err(EmptyBal) } else { Ok(Self(value)) }
1188 }
1189 }
1190
1191 #[test]
1192 fn decoded_bal_convert_and_try_convert_use_inner_conversions() {
1193 let raw = Bytes::from_static(&[0xc0]);
1194 let converted: DecodedBal<BalLen> = DecodedBal::new(Bal::default(), raw.clone()).convert();
1195
1196 assert_eq!(converted.as_bal(), &BalLen(0));
1197 assert_eq!(converted.as_raw(), &raw);
1198
1199 let err = DecodedBal::new(Bal::default(), raw.clone()).try_convert::<NonEmptyBal>();
1200 assert_eq!(err.unwrap_err(), EmptyBal);
1201
1202 let bal = Bal::new(vec![AccountChanges::new(Address::from([0x11; 20]))]);
1203 let converted = DecodedBal::new(bal, raw).try_convert::<NonEmptyBal>().unwrap();
1204
1205 assert_eq!(converted.as_bal().0.len(), 1);
1206 }
1207
1208 #[test]
1209 fn decoded_bal_ensure_hash_reports_both_hashes() {
1210 let raw = Bytes::from_static(&[0xc0]);
1211 let decoded = DecodedBal::new(Bal::default(), raw.clone());
1212 let computed = alloy_primitives::keccak256(raw.as_ref());
1213 let expected = B256::from([0x11; 32]);
1214
1215 assert_eq!(decoded.ensure_hash(computed), Ok(()));
1216 assert_eq!(
1217 decoded.ensure_hash(expected),
1218 Err(super::BlockAccessListHashMismatch::new(computed, expected))
1219 );
1220 }
1221
1222 #[test]
1223 fn raw_bal_hash_uses_raw_bytes() {
1224 let raw = Bytes::from_static(&[0xc0]);
1225 let raw_bal = RawBal::new(raw.clone());
1226 let computed = alloy_primitives::keccak256(raw.as_ref());
1227 let expected = B256::from([0x11; 32]);
1228
1229 assert_eq!(raw_bal.as_raw(), &raw);
1230 assert_eq!(raw_bal.hash(), computed);
1231 assert_eq!(raw_bal.ensure_hash(computed), Ok(()));
1232 assert_eq!(
1233 raw_bal.ensure_hash(expected),
1234 Err(super::BlockAccessListHashMismatch::new(computed, expected))
1235 );
1236
1237 let (split_raw, split_hash) = raw_bal.into_parts();
1238 assert_eq!(split_raw, raw);
1239 assert_eq!(split_hash, computed);
1240 }
1241
1242 #[test]
1243 fn raw_bal_new_unchecked_uses_supplied_hash() {
1244 let raw = Bytes::from_static(&[0xc0]);
1245 let hash = B256::from([0x11; 32]);
1246 let raw_bal = RawBal::new_unchecked(raw.clone(), hash);
1247
1248 assert_eq!(raw_bal.as_raw(), &raw);
1249 assert_eq!(raw_bal.hash(), hash);
1250 assert_eq!(raw_bal.ensure_hash(hash), Ok(()));
1251
1252 let (split_raw, split_hash) = raw_bal.into_parts();
1253 assert_eq!(split_raw, raw);
1254 assert_eq!(split_hash, hash);
1255 }
1256
1257 #[test]
1258 fn decoded_bal_exposes_raw_bal() {
1259 let raw = Bytes::from_static(&[0xc0]);
1260 let raw_bal = RawBal::new(raw.clone());
1261 let decoded = DecodedBal::with_raw_bal(Bal::default(), raw_bal.clone());
1262
1263 assert_eq!(decoded.as_raw_bal(), &raw_bal);
1264 assert_eq!(decoded.as_raw(), &raw);
1265
1266 let (bal, split_raw_bal) = decoded.split_raw_bal();
1267 assert!(bal.is_empty());
1268 assert_eq!(split_raw_bal, raw_bal);
1269 }
1270
1271 #[test]
1272 fn decoded_bal_new_unchecked_uses_supplied_hash() {
1273 let raw = Bytes::from_static(&[0xc0]);
1274 let hash = B256::from([0x11; 32]);
1275 let decoded = DecodedBal::new_unchecked(Bal::default(), raw.clone(), hash);
1276
1277 assert_eq!(decoded.as_raw(), &raw);
1278 assert_eq!(decoded.hash(), hash);
1279 assert_eq!(decoded.ensure_hash(hash), Ok(()));
1280 }
1281
1282 #[cfg(feature = "serde")]
1283 #[test]
1284 fn decoded_bal_serde_keeps_raw_bytes_field() {
1285 let raw = Bytes::from_static(&[0xc0]);
1286 let decoded = DecodedBal::new(Bal::default(), raw.clone());
1287 let value = serde_json::to_value(&decoded).unwrap();
1288
1289 assert!(value.get("decoded").is_some());
1290 assert_eq!(value.get("raw"), Some(&serde_json::to_value(&raw).unwrap()));
1291 assert!(value.get("hash").is_none());
1292
1293 let decoded = serde_json::from_value::<DecodedBal>(value).unwrap();
1294 assert_eq!(decoded.as_bal(), &Bal::default());
1295 assert_eq!(decoded.as_raw(), &raw);
1296 }
1297
1298 #[test]
1299 fn raw_or_decoded_bal_raw_helpers_use_raw_bytes() {
1300 let raw = Bytes::from_static(&[0xc0]);
1301 let bal = RawOrDecodedBal::<Bal>::raw(raw.clone());
1302 let hash = alloy_primitives::keccak256(raw.as_ref());
1303
1304 assert!(bal.is_raw());
1305 assert!(!bal.is_decoded());
1306 assert_eq!(bal.as_raw(), &raw);
1307 assert_eq!(bal.as_raw_bal().as_raw(), &raw);
1308 assert_eq!(bal.as_decoded(), None);
1309 assert_eq!(bal.as_bal(), None);
1310 assert_eq!(bal.hash(), hash);
1311 assert_eq!(bal.ensure_hash(hash), Ok(()));
1312
1313 let (decoded, split_raw) = bal.clone().split();
1314 assert_eq!(decoded, None);
1315 assert_eq!(split_raw, raw);
1316 let (decoded, split_raw_bal) = bal.clone().split_raw_bal();
1317 assert_eq!(decoded, None);
1318 assert_eq!(split_raw_bal.as_raw(), &raw);
1319 assert_eq!(bal.clone().into_raw_bal().as_raw(), &raw);
1320 assert_eq!(bal.into_raw(), raw);
1321 }
1322
1323 #[test]
1324 fn raw_or_decoded_bal_raw_unchecked_uses_supplied_hash() {
1325 let raw = Bytes::from_static(&[0xc0]);
1326 let hash = B256::from([0x11; 32]);
1327 let bal = RawOrDecodedBal::<Bal>::raw_unchecked(raw.clone(), hash);
1328
1329 assert!(bal.is_raw());
1330 assert_eq!(bal.as_raw(), &raw);
1331 assert_eq!(bal.hash(), hash);
1332 assert_eq!(bal.ensure_hash(hash), Ok(()));
1333 }
1334
1335 #[test]
1336 fn raw_or_decoded_bal_decoded_helpers_use_decoded_bal() {
1337 let raw = Bytes::from_static(&[0xc0]);
1338 let decoded = DecodedBal::new(Bal::default(), raw.clone());
1339 let hash = decoded.hash();
1340 let bal = RawOrDecodedBal::decoded(decoded.clone());
1341
1342 assert!(!bal.is_raw());
1343 assert!(bal.is_decoded());
1344 assert_eq!(bal.as_raw(), &raw);
1345 assert_eq!(bal.as_raw_bal(), decoded.as_raw_bal());
1346 assert_eq!(bal.as_decoded(), Some(&decoded));
1347 assert_eq!(bal.as_bal(), Some(decoded.as_bal()));
1348 assert_eq!(bal.hash(), hash);
1349
1350 let (split_bal, split_raw) = bal.clone().split();
1351 assert_eq!(split_bal, Some(Bal::default()));
1352 assert_eq!(split_raw, raw);
1353 let (split_bal, split_raw_bal) = bal.clone().split_raw_bal();
1354 assert_eq!(split_bal, Some(Bal::default()));
1355 assert_eq!(split_raw_bal.as_raw(), &raw);
1356 assert_eq!(bal.into_decoded(), Some(decoded));
1357 }
1358
1359 #[test]
1360 fn raw_or_decoded_bal_convert_maps_only_decoded_values() {
1361 let raw = Bytes::from_static(&[0xc0]);
1362 let raw_bal: RawOrDecodedBal<Bal> = RawOrDecodedBal::raw(raw.clone());
1363 let converted_raw: RawOrDecodedBal<BalLen> = raw_bal.convert();
1364
1365 assert!(converted_raw.is_raw());
1366 assert_eq!(converted_raw.as_raw(), &raw);
1367 assert_eq!(converted_raw.as_bal(), None);
1368
1369 let decoded = DecodedBal::new(Bal::default(), raw.clone());
1370 let converted_decoded: RawOrDecodedBal<BalLen> =
1371 RawOrDecodedBal::decoded(decoded).convert();
1372
1373 assert!(converted_decoded.is_decoded());
1374 assert_eq!(converted_decoded.as_bal(), Some(&BalLen(0)));
1375 assert_eq!(converted_decoded.as_raw(), &raw);
1376
1377 let err = RawOrDecodedBal::decoded(DecodedBal::new(Bal::default(), raw.clone()))
1378 .try_convert::<NonEmptyBal>();
1379 assert_eq!(err.unwrap_err(), EmptyBal);
1380
1381 let raw_result: Result<RawOrDecodedBal<NonEmptyBal>, EmptyBal> =
1382 RawOrDecodedBal::<Bal>::raw(raw.clone()).try_convert();
1383 let raw_result = raw_result.unwrap();
1384 assert!(raw_result.is_raw());
1385 assert_eq!(raw_result.as_raw(), &raw);
1386 }
1387
1388 #[test]
1389 fn bal_merge_combines_duplicate_accounts_and_appends_new_accounts() {
1390 let existing_address = Address::from([0x11; 20]);
1391 let new_address = Address::from([0x22; 20]);
1392 let mut bal = Bal::new(vec![
1393 AccountChanges {
1394 address: existing_address,
1395 storage_changes: vec![SlotChanges::new(
1396 U256::from(1),
1397 vec![StorageChange::new(BlockAccessIndex::new(0), U256::from(10))],
1398 )],
1399 storage_reads: vec![U256::from(2)],
1400 balance_changes: vec![BalanceChange::new(
1401 BlockAccessIndex::new(1),
1402 U256::from(100),
1403 )],
1404 nonce_changes: vec![],
1405 code_changes: vec![],
1406 },
1407 AccountChanges::new(existing_address).with_code_change(CodeChange::new(
1408 BlockAccessIndex::new(5),
1409 Bytes::from_static(&[0xbb]),
1410 )),
1411 ]);
1412
1413 bal.merge([
1414 AccountChanges {
1415 address: existing_address,
1416 storage_changes: vec![SlotChanges::new(
1417 U256::from(2),
1418 vec![StorageChange::new(BlockAccessIndex::new(2), U256::from(20))],
1419 )],
1420 storage_reads: vec![U256::from(1), U256::from(3), U256::from(3)],
1421 balance_changes: vec![BalanceChange::new(
1422 BlockAccessIndex::new(3),
1423 U256::from(200),
1424 )],
1425 nonce_changes: vec![],
1426 code_changes: vec![],
1427 },
1428 AccountChanges::new(new_address)
1429 .with_nonce_change(NonceChange::new(BlockAccessIndex::new(4), 7)),
1430 ]);
1431
1432 assert_eq!(bal.len(), 2);
1433 assert_eq!(bal[0].address, existing_address);
1434 assert_eq!(bal[1].address, new_address);
1435 assert_eq!(
1436 bal[0].storage_changes.iter().map(|changes| changes.slot).collect::<Vec<_>>(),
1437 vec![U256::from(1), U256::from(2)]
1438 );
1439 assert_eq!(bal[0].storage_reads, vec![U256::from(3)]);
1440 assert_eq!(
1441 bal[0]
1442 .balance_changes
1443 .iter()
1444 .map(|change| change.block_access_index)
1445 .collect::<Vec<_>>(),
1446 vec![BlockAccessIndex::new(1), BlockAccessIndex::new(3)]
1447 );
1448 assert_eq!(
1449 bal[0].code_changes,
1450 vec![CodeChange::new(BlockAccessIndex::new(5), Bytes::from_static(&[0xbb]))]
1451 );
1452 assert_eq!(bal[1].nonce_changes, vec![NonceChange::new(BlockAccessIndex::new(4), 7)]);
1453 }
1454
1455 #[test]
1456 fn bal_merge_collapses_duplicate_accounts_from_incoming_iterator() {
1457 let address = Address::from([0x11; 20]);
1458 let mut bal = Bal::default();
1459
1460 bal.merge([
1461 AccountChanges::new(address)
1462 .with_balance_change(BalanceChange::new(BlockAccessIndex::new(0), U256::from(100))),
1463 AccountChanges::new(address).with_code_change(CodeChange::new(
1464 BlockAccessIndex::new(1),
1465 Bytes::from_static(&[0xaa]),
1466 )),
1467 ]);
1468
1469 assert_eq!(bal.len(), 1);
1470 assert_eq!(bal[0].balance_changes.len(), 1);
1471 assert_eq!(
1472 bal[0].code_changes,
1473 vec![CodeChange::new(BlockAccessIndex::new(1), Bytes::from_static(&[0xaa]))]
1474 );
1475 }
1476
1477 #[test]
1478 fn bal_insert_changes_shifts_suffix_and_normalizes_inserted_layer() {
1479 let existing_address = Address::from([0x22; 20]);
1480 let new_address = Address::from([0x11; 20]);
1481 let slot = U256::from(1);
1482 let mut bal = Bal::new(vec![AccountChanges {
1483 address: existing_address,
1484 storage_changes: vec![SlotChanges::new(
1485 slot,
1486 vec![StorageChange::new(BlockAccessIndex::new(2), U256::from(20))],
1487 )],
1488 storage_reads: vec![U256::from(2)],
1489 balance_changes: vec![
1490 BalanceChange::new(BlockAccessIndex::new(1), U256::from(100)),
1491 BalanceChange::new(BlockAccessIndex::new(2), U256::from(200)),
1492 BalanceChange::new(BlockAccessIndex::new(3), U256::from(300)),
1493 ],
1494 nonce_changes: vec![NonceChange::new(BlockAccessIndex::new(2), 2)],
1495 code_changes: vec![CodeChange::new(
1496 BlockAccessIndex::new(2),
1497 Bytes::from_static(&[0x60, 0x02]),
1498 )],
1499 }]);
1500
1501 let positioned_index = bal.insert_changes_at(
1502 BlockAccessIndex::new(2),
1503 [
1504 AccountChanges::new(existing_address)
1505 .with_storage_change(SlotChanges::new(
1506 slot,
1507 vec![StorageChange::new(BlockAccessIndex::new(90), U256::from(900))],
1508 ))
1509 .with_balance_change(BalanceChange::new(
1510 BlockAccessIndex::new(90),
1511 U256::from(900),
1512 )),
1513 AccountChanges::new(existing_address)
1514 .with_storage_change(SlotChanges::new(
1515 slot,
1516 vec![StorageChange::new(BlockAccessIndex::new(91), U256::from(901))],
1517 ))
1518 .with_balance_change(BalanceChange::new(
1519 BlockAccessIndex::new(91),
1520 U256::from(901),
1521 ))
1522 .with_nonce_change(NonceChange::new(BlockAccessIndex::new(91), 9)),
1523 AccountChanges::new(new_address).with_code_change(CodeChange::new(
1524 BlockAccessIndex::new(92),
1525 Bytes::from_static(&[0x60, 0x09]),
1526 )),
1527 ],
1528 );
1529
1530 assert_eq!(positioned_index, BlockAccessIndex::new(3));
1531 assert_eq!(
1532 bal.iter().map(AccountChanges::address).collect::<Vec<_>>(),
1533 vec![new_address, existing_address]
1534 );
1535
1536 assert_eq!(
1537 bal[0].code_changes,
1538 vec![CodeChange::new(BlockAccessIndex::new(2), Bytes::from_static(&[0x60, 0x09]))]
1539 );
1540 assert_eq!(
1541 bal[1].balance_changes,
1542 vec![
1543 BalanceChange::new(BlockAccessIndex::new(1), U256::from(100)),
1544 BalanceChange::new(BlockAccessIndex::new(2), U256::from(901)),
1545 BalanceChange::new(BlockAccessIndex::new(3), U256::from(200)),
1546 BalanceChange::new(BlockAccessIndex::new(4), U256::from(300)),
1547 ]
1548 );
1549 assert_eq!(
1550 bal[1].storage_changes[0].changes,
1551 vec![
1552 StorageChange::new(BlockAccessIndex::new(2), U256::from(901)),
1553 StorageChange::new(BlockAccessIndex::new(3), U256::from(20)),
1554 ]
1555 );
1556 assert_eq!(
1557 bal[1].nonce_changes,
1558 vec![
1559 NonceChange::new(BlockAccessIndex::new(2), 9),
1560 NonceChange::new(BlockAccessIndex::new(3), 2),
1561 ]
1562 );
1563 assert_eq!(
1564 bal[1].code_changes,
1565 vec![CodeChange::new(BlockAccessIndex::new(3), Bytes::from_static(&[0x60, 0x02]))]
1566 );
1567 assert_eq!(bal[1].storage_reads, vec![U256::from(2)]);
1568 }
1569
1570 #[test]
1571 fn bal_insert_empty_changes_is_noop() {
1572 let original =
1573 Bal::new(vec![AccountChanges::new(Address::from([0x11; 20])).with_balance_change(
1574 BalanceChange::new(BlockAccessIndex::new(1), U256::from(100)),
1575 )]);
1576 let mut bal = original.clone();
1577
1578 let positioned_index = bal.insert_changes_at(
1579 BlockAccessIndex::new(1),
1580 [AccountChanges::new(Address::from([0x22; 20]))],
1581 );
1582
1583 assert_eq!(positioned_index, BlockAccessIndex::new(1));
1584 assert_eq!(bal, original);
1585 }
1586
1587 #[test]
1588 fn bal_insert_shifts_untouched_accounts() {
1589 let touched = Address::from([0x11; 20]);
1590 let bystander = Address::from([0x22; 20]);
1591 let mut bal = Bal::new(vec![
1592 AccountChanges::new(touched)
1593 .with_balance_change(BalanceChange::new(BlockAccessIndex::new(2), U256::from(100))),
1594 AccountChanges::new(bystander)
1595 .with_storage_change(SlotChanges::new(
1596 U256::from(1),
1597 vec![StorageChange::new(BlockAccessIndex::new(2), U256::from(20))],
1598 ))
1599 .with_balance_change(BalanceChange::new(BlockAccessIndex::new(1), U256::from(50)))
1600 .with_nonce_change(NonceChange::new(BlockAccessIndex::new(2), 7))
1601 .with_code_change(CodeChange::new(
1602 BlockAccessIndex::new(3),
1603 Bytes::from_static(&[0x60]),
1604 )),
1605 ]);
1606
1607 let positioned_index = bal.insert_changes_at(
1608 BlockAccessIndex::new(2),
1609 [AccountChanges::new(touched).with_balance_change(BalanceChange::new(
1610 BlockAccessIndex::new(0),
1611 U256::from(900),
1612 ))],
1613 );
1614
1615 assert_eq!(positioned_index, BlockAccessIndex::new(3));
1616 assert_eq!(
1617 bal[0].balance_changes,
1618 vec![
1619 BalanceChange::new(BlockAccessIndex::new(2), U256::from(900)),
1620 BalanceChange::new(BlockAccessIndex::new(3), U256::from(100)),
1621 ]
1622 );
1623 assert_eq!(bal[1].address, bystander);
1624 assert_eq!(
1625 bal[1].storage_changes,
1626 vec![SlotChanges::new(
1627 U256::from(1),
1628 vec![StorageChange::new(BlockAccessIndex::new(3), U256::from(20))],
1629 )]
1630 );
1631 assert_eq!(
1632 bal[1].balance_changes,
1633 vec![BalanceChange::new(BlockAccessIndex::new(1), U256::from(50))]
1634 );
1635 assert_eq!(bal[1].nonce_changes, vec![NonceChange::new(BlockAccessIndex::new(3), 7)]);
1636 assert_eq!(
1637 bal[1].code_changes,
1638 vec![CodeChange::new(BlockAccessIndex::new(4), Bytes::from_static(&[0x60]))]
1639 );
1640 }
1641
1642 #[test]
1643 fn bal_insert_folds_duplicate_slot_entries() {
1644 let slot = U256::from(7);
1645
1646 let new_address = Address::from([0x11; 20]);
1647 let mut bal = Bal::default();
1648 let positioned_index = bal.insert_changes_at(
1649 BlockAccessIndex::new(1),
1650 [AccountChanges::new(new_address)
1651 .with_storage_change(SlotChanges::new(
1652 slot,
1653 vec![StorageChange::new(BlockAccessIndex::new(90), U256::from(900))],
1654 ))
1655 .with_storage_change(SlotChanges::new(
1656 slot,
1657 vec![StorageChange::new(BlockAccessIndex::new(91), U256::from(901))],
1658 ))],
1659 );
1660 assert_eq!(positioned_index, BlockAccessIndex::new(2));
1661 assert_eq!(
1662 bal[0].storage_changes,
1663 vec![SlotChanges::new(
1664 slot,
1665 vec![StorageChange::new(BlockAccessIndex::new(1), U256::from(901))],
1666 )]
1667 );
1668
1669 let existing = Address::from([0x22; 20]);
1670 let mut bal =
1671 Bal::new(vec![AccountChanges::new(existing).with_storage_change(SlotChanges::new(
1672 slot,
1673 vec![StorageChange::new(BlockAccessIndex::new(1), U256::from(10))],
1674 ))]);
1675 let positioned_index = bal.insert_changes_at(
1676 BlockAccessIndex::new(1),
1677 [AccountChanges::new(existing)
1678 .with_storage_change(SlotChanges::new(
1679 slot,
1680 vec![StorageChange::new(BlockAccessIndex::new(90), U256::from(900))],
1681 ))
1682 .with_storage_change(SlotChanges::new(
1683 slot,
1684 vec![StorageChange::new(BlockAccessIndex::new(91), U256::from(901))],
1685 ))],
1686 );
1687 assert_eq!(positioned_index, BlockAccessIndex::new(2));
1688 assert_eq!(
1689 bal[0].storage_changes,
1690 vec![SlotChanges::new(
1691 slot,
1692 vec![
1693 StorageChange::new(BlockAccessIndex::new(1), U256::from(901)),
1694 StorageChange::new(BlockAccessIndex::new(2), U256::from(10)),
1695 ],
1696 )]
1697 );
1698 }
1699
1700 #[test]
1701 fn bal_insert_normalizes_reads_for_new_accounts() {
1702 let address = Address::from([0x11; 20]);
1703 let written = U256::from(1);
1704 let read = U256::from(2);
1705 let mut bal = Bal::default();
1706
1707 let positioned_index = bal.insert_changes_at(
1708 BlockAccessIndex::new(0),
1709 [AccountChanges::new(address)
1710 .with_storage_read(written)
1711 .with_storage_read(read)
1712 .with_storage_read(read)
1713 .with_storage_change(SlotChanges::new(
1714 written,
1715 vec![StorageChange::new(BlockAccessIndex::new(9), U256::from(90))],
1716 ))],
1717 );
1718
1719 assert_eq!(positioned_index, BlockAccessIndex::new(1));
1720 assert_eq!(
1721 bal[0].storage_changes,
1722 vec![SlotChanges::new(
1723 written,
1724 vec![StorageChange::new(BlockAccessIndex::new(0), U256::from(90))],
1725 )]
1726 );
1727 assert_eq!(bal[0].storage_reads, vec![read]);
1728 }
1729
1730 #[test]
1731 fn bal_insert_empty_slot_entries_are_noop() {
1732 let original =
1733 Bal::new(vec![AccountChanges::new(Address::from([0x11; 20])).with_balance_change(
1734 BalanceChange::new(BlockAccessIndex::new(1), U256::from(100)),
1735 )]);
1736 let mut bal = original.clone();
1737
1738 let positioned_index = bal.insert_changes_at(
1739 BlockAccessIndex::new(1),
1740 [AccountChanges::new(Address::from([0x22; 20]))
1741 .with_storage_change(SlotChanges::new(U256::from(1), vec![]))],
1742 );
1743
1744 assert_eq!(positioned_index, BlockAccessIndex::new(1));
1745 assert_eq!(bal, original);
1746 }
1747
1748 #[test]
1749 fn bal_insert_empty_slot_entry_does_not_swallow_read() {
1750 let address = Address::from([0x11; 20]);
1751 let slot = U256::from(42);
1752 let mut bal = Bal::default();
1753
1754 let positioned_index = bal.insert_changes_at(
1755 BlockAccessIndex::new(3),
1756 [
1757 AccountChanges::new(address).with_storage_read(slot),
1758 AccountChanges::new(address).with_storage_change(SlotChanges::new(slot, vec![])),
1759 ],
1760 );
1761
1762 assert_eq!(positioned_index, BlockAccessIndex::new(3));
1763 assert_eq!(bal[0].storage_reads, vec![slot]);
1764 assert!(bal[0].storage_changes.is_empty());
1765 }
1766
1767 #[test]
1768 fn bal_insert_reads_only_does_not_shift() {
1769 let address = Address::from([0x11; 20]);
1770 let written = U256::from(1);
1771 let mut bal =
1772 Bal::new(vec![AccountChanges::new(address).with_storage_change(SlotChanges::new(
1773 written,
1774 vec![StorageChange::new(BlockAccessIndex::new(4), U256::from(40))],
1775 ))]);
1776 let original = bal.clone();
1777
1778 let positioned_index = bal.insert_changes_at(
1780 BlockAccessIndex::new(1),
1781 [AccountChanges::new(address).with_storage_read(written)],
1782 );
1783 assert_eq!(positioned_index, BlockAccessIndex::new(1));
1784 assert_eq!(bal, original);
1785
1786 let novel = U256::from(2);
1788 let positioned_index = bal.insert_changes_at(
1789 BlockAccessIndex::new(1),
1790 [AccountChanges::new(address).with_storage_read(novel)],
1791 );
1792 assert_eq!(positioned_index, BlockAccessIndex::new(1));
1793 assert_eq!(bal[0].storage_reads, vec![novel]);
1794 assert_eq!(bal[0].storage_changes, original[0].storage_changes);
1795 }
1796
1797 #[test]
1798 fn bal_insert_saturates_index_overflow() {
1799 let address = Address::from([0x11; 20]);
1800 let mut bal = Bal::new(vec![AccountChanges::new(address).with_balance_change(
1801 BalanceChange::new(BlockAccessIndex::new(u64::MAX), U256::from(1)),
1802 )]);
1803
1804 let positioned_index = bal.insert_changes_at(
1805 BlockAccessIndex::new(u64::MAX),
1806 [AccountChanges::new(address)
1807 .with_nonce_change(NonceChange::new(BlockAccessIndex::new(0), 1))],
1808 );
1809
1810 assert_eq!(positioned_index, BlockAccessIndex::new(u64::MAX));
1811 assert_eq!(
1812 bal[0].balance_changes,
1813 vec![BalanceChange::new(BlockAccessIndex::new(u64::MAX), U256::from(1))]
1814 );
1815 assert_eq!(
1816 bal[0].nonce_changes,
1817 vec![NonceChange::new(BlockAccessIndex::new(u64::MAX), 1)]
1818 );
1819 }
1820
1821 #[test]
1824 fn bal_insert_applies_state_overrides() {
1825 let alice = Address::from([0xaa; 20]);
1826 let bob = Address::from([0xbb; 20]);
1827 let slot = U256::from(1);
1828
1829 let mut bal = Bal::new(vec![
1832 AccountChanges::new(alice)
1833 .with_storage_change(SlotChanges::new(
1834 slot,
1835 vec![
1836 StorageChange::new(BlockAccessIndex::new(2), U256::from(20)),
1837 StorageChange::new(BlockAccessIndex::new(3), U256::from(30)),
1838 ],
1839 ))
1840 .with_balance_change(BalanceChange::new(BlockAccessIndex::new(1), U256::from(100)))
1841 .with_balance_change(BalanceChange::new(BlockAccessIndex::new(2), U256::from(200)))
1842 .with_balance_change(BalanceChange::new(BlockAccessIndex::new(3), U256::from(300))),
1843 ]);
1844
1845 let balance_at = |account: &AccountChanges, position: BlockAccessIndex| {
1847 account
1848 .balance_changes
1849 .iter()
1850 .rfind(|change| change.block_access_index < position)
1851 .map(|change| change.post_balance)
1852 };
1853 let position = BlockAccessIndex::new(2);
1854 assert_eq!(balance_at(&bal[0], position), Some(U256::from(100)));
1855
1856 let overrides = [
1859 (alice, Some(U256::from(999)), None, None, vec![(slot, U256::from(90))]),
1860 (
1861 bob,
1862 None,
1863 Some(7),
1864 Some(Bytes::from_static(&[0x60, 0x00])),
1865 vec![(U256::from(5), U256::from(50))],
1866 ),
1867 (alice, Some(U256::from(1000)), None, None, vec![]),
1869 ];
1870
1871 let placeholder = BlockAccessIndex::PRE_EXECUTION;
1874 let overlay = overrides.into_iter().map(|(address, balance, nonce, code, slots)| {
1875 let mut account = AccountChanges::new(address);
1876 if let Some(balance) = balance {
1877 account = account.with_balance_change(BalanceChange::new(placeholder, balance));
1878 }
1879 if let Some(nonce) = nonce {
1880 account = account.with_nonce_change(NonceChange::new(placeholder, nonce));
1881 }
1882 if let Some(code) = code {
1883 account = account.with_code_change(CodeChange::new(placeholder, code));
1884 }
1885 for (slot, value) in slots {
1886 account = account.with_storage_change(SlotChanges::new(
1887 slot,
1888 vec![StorageChange::new(placeholder, value)],
1889 ));
1890 }
1891 account
1892 });
1893
1894 let positioned_index = bal.insert_changes_at(position, overlay);
1895 assert_eq!(positioned_index, BlockAccessIndex::new(3));
1896
1897 assert_eq!(
1899 bal[0].balance_changes,
1900 vec![
1901 BalanceChange::new(BlockAccessIndex::new(1), U256::from(100)),
1902 BalanceChange::new(BlockAccessIndex::new(2), U256::from(1000)),
1903 BalanceChange::new(BlockAccessIndex::new(3), U256::from(200)),
1904 BalanceChange::new(BlockAccessIndex::new(4), U256::from(300)),
1905 ]
1906 );
1907 assert_eq!(
1908 bal[0].storage_changes,
1909 vec![SlotChanges::new(
1910 slot,
1911 vec![
1912 StorageChange::new(BlockAccessIndex::new(2), U256::from(90)),
1913 StorageChange::new(BlockAccessIndex::new(3), U256::from(20)),
1914 StorageChange::new(BlockAccessIndex::new(4), U256::from(30)),
1915 ],
1916 )]
1917 );
1918 assert_eq!(bal[1].address, bob);
1919 assert_eq!(bal[1].nonce_changes, vec![NonceChange::new(BlockAccessIndex::new(2), 7)]);
1920 assert_eq!(
1921 bal[1].code_changes,
1922 vec![CodeChange::new(BlockAccessIndex::new(2), Bytes::from_static(&[0x60, 0x00]))]
1923 );
1924 assert_eq!(
1925 bal[1].storage_changes,
1926 vec![SlotChanges::new(
1927 U256::from(5),
1928 vec![StorageChange::new(BlockAccessIndex::new(2), U256::from(50))],
1929 )]
1930 );
1931
1932 assert_eq!(balance_at(&bal[0], position), Some(U256::from(100)));
1935 assert_eq!(balance_at(&bal[0], positioned_index), Some(U256::from(1000)));
1936 assert_eq!(balance_at(&bal[0], BlockAccessIndex::new(5)), Some(U256::from(300)));
1937 }
1938
1939 #[test]
1940 fn bal_sort_orders_all_eip7928_lists() {
1941 let address_1 = Address::from([0x11; 20]);
1942 let address_2 = Address::from([0x22; 20]);
1943 let mut bal = Bal::new(vec![
1944 AccountChanges {
1945 address: address_2,
1946 storage_changes: vec![
1947 SlotChanges::new(
1948 U256::from(3),
1949 vec![
1950 StorageChange::new(BlockAccessIndex::new(8), U256::from(0x80)),
1951 StorageChange::new(BlockAccessIndex::new(2), U256::from(0x20)),
1952 ],
1953 ),
1954 SlotChanges::new(
1955 U256::from(1),
1956 vec![
1957 StorageChange::new(BlockAccessIndex::new(5), U256::from(0x50)),
1958 StorageChange::new(BlockAccessIndex::new(1), U256::from(0x10)),
1959 ],
1960 ),
1961 ],
1962 storage_reads: vec![U256::from(4), U256::from(2)],
1963 balance_changes: vec![
1964 BalanceChange::new(BlockAccessIndex::new(6), U256::from(600)),
1965 BalanceChange::new(BlockAccessIndex::new(3), U256::from(300)),
1966 ],
1967 nonce_changes: vec![
1968 NonceChange::new(BlockAccessIndex::new(7), 70),
1969 NonceChange::new(BlockAccessIndex::new(4), 40),
1970 ],
1971 code_changes: vec![
1972 CodeChange::new(BlockAccessIndex::new(9), Bytes::from_static(&[0x60, 0x09])),
1973 CodeChange::new(BlockAccessIndex::new(5), Bytes::from_static(&[0x60, 0x05])),
1974 ],
1975 },
1976 AccountChanges {
1977 address: address_1,
1978 storage_changes: vec![
1979 SlotChanges::new(
1980 U256::from(2),
1981 vec![
1982 StorageChange::new(BlockAccessIndex::new(4), U256::from(0x40)),
1983 StorageChange::new(BlockAccessIndex::new(0), U256::from(0x00)),
1984 ],
1985 ),
1986 SlotChanges::new(
1987 U256::from(1),
1988 vec![
1989 StorageChange::new(BlockAccessIndex::new(3), U256::from(0x30)),
1990 StorageChange::new(BlockAccessIndex::new(1), U256::from(0x10)),
1991 ],
1992 ),
1993 ],
1994 storage_reads: vec![U256::from(5), U256::from(3)],
1995 balance_changes: vec![
1996 BalanceChange::new(BlockAccessIndex::new(5), U256::from(500)),
1997 BalanceChange::new(BlockAccessIndex::new(2), U256::from(200)),
1998 ],
1999 nonce_changes: vec![
2000 NonceChange::new(BlockAccessIndex::new(8), 80),
2001 NonceChange::new(BlockAccessIndex::new(1), 10),
2002 ],
2003 code_changes: vec![
2004 CodeChange::new(BlockAccessIndex::new(4), Bytes::from_static(&[0x60, 0x04])),
2005 CodeChange::new(BlockAccessIndex::new(2), Bytes::from_static(&[0x60, 0x02])),
2006 ],
2007 },
2008 ]);
2009
2010 bal.sort();
2011
2012 assert_eq!(bal[0].address, address_1);
2013 assert_eq!(bal[1].address, address_2);
2014
2015 for account in bal.iter() {
2016 assert!(account.storage_changes.windows(2).all(|slots| slots[0].slot <= slots[1].slot));
2017 for slot_changes in &account.storage_changes {
2018 assert!(
2019 slot_changes
2020 .changes
2021 .windows(2)
2022 .all(|changes| changes[0].block_access_index
2023 <= changes[1].block_access_index)
2024 );
2025 }
2026 assert!(account.storage_reads.windows(2).all(|slots| slots[0] <= slots[1]));
2027 assert!(
2028 account
2029 .balance_changes
2030 .windows(2)
2031 .all(|changes| changes[0].block_access_index <= changes[1].block_access_index)
2032 );
2033 assert!(
2034 account
2035 .nonce_changes
2036 .windows(2)
2037 .all(|changes| changes[0].block_access_index <= changes[1].block_access_index)
2038 );
2039 assert!(
2040 account
2041 .code_changes
2042 .windows(2)
2043 .all(|changes| changes[0].block_access_index <= changes[1].block_access_index)
2044 );
2045 }
2046 }
2047
2048 #[test]
2049 fn bal_validate_gas_limit_accepts_exact_item_cost() {
2050 let bal = Bal::new(vec![
2051 AccountChanges::new(Address::from([0x11; 20]))
2052 .with_storage_read(U256::from(1))
2053 .with_storage_change(SlotChanges::new(
2054 U256::from(2),
2055 vec![StorageChange::new(BlockAccessIndex::new(0), U256::from(0xaa))],
2056 )),
2057 ]);
2058
2059 assert_eq!(bal.total_bal_items(), 3);
2060 assert_eq!(bal.validate_gas_limit(3 * ITEM_COST as u64), Ok(()));
2061 }
2062
2063 #[test]
2064 fn bal_total_items_counts_storage_entries_without_deduplicating() {
2065 let bal = Bal::new(vec![
2066 AccountChanges::new(Address::from([0x11; 20]))
2067 .with_storage_read(U256::from(1))
2068 .with_storage_change(SlotChanges::new(
2069 U256::from(1),
2070 vec![StorageChange::new(BlockAccessIndex::new(0), U256::from(0xaa))],
2071 )),
2072 ]);
2073
2074 assert_eq!(bal.total_bal_items(), 3);
2075 }
2076
2077 #[test]
2078 fn bal_validate_gas_limit_rejects_item_cost_above_limit() {
2079 let bal = Bal::new(vec![
2080 AccountChanges::new(Address::from([0x11; 20]))
2081 .with_storage_read(U256::from(1))
2082 .with_storage_read(U256::from(2)),
2083 ]);
2084 let gas_limit = 3 * ITEM_COST as u64 - 1;
2085
2086 assert_eq!(bal.total_bal_items(), 3);
2087 assert_eq!(
2088 bal.validate_gas_limit(gas_limit),
2089 Err(super::BlockAccessListGasError::new(3, gas_limit))
2090 );
2091 }
2092}
2093
2094#[cfg(all(test, feature = "rlp"))]
2095mod tests {
2096 use super::bal::{Bal, DecodedBal, RawBal, RawOrDecodedBal};
2097 use crate::{
2098 AccountChanges, BalanceChange, BlockAccessIndex, CodeChange, NonceChange, SlotChanges,
2099 StorageChange, constants::EMPTY_BLOCK_ACCESS_LIST_HASH,
2100 };
2101 use alloy_primitives::{Address, Bytes, U256};
2102
2103 fn sample_bal() -> Bal {
2104 Bal::new(vec![
2105 AccountChanges::new(Address::from([0x11; 20]))
2106 .with_storage_read(U256::from(0x10))
2107 .with_storage_change(SlotChanges::new(
2108 U256::from(0x01),
2109 vec![StorageChange::new(BlockAccessIndex::new(0), U256::from(0xaa))],
2110 ))
2111 .with_balance_change(BalanceChange::new(
2112 BlockAccessIndex::new(1),
2113 U256::from(1_000),
2114 ))
2115 .with_nonce_change(NonceChange::new(BlockAccessIndex::new(2), 7))
2116 .with_code_change(CodeChange::new(
2117 BlockAccessIndex::new(3),
2118 Bytes::from(vec![0x60, 0x00]),
2119 )),
2120 AccountChanges::new(Address::from([0x22; 20]))
2121 .with_storage_read(U256::from(0x20))
2122 .with_storage_change(SlotChanges::new(
2123 U256::from(0x02),
2124 vec![StorageChange::new(BlockAccessIndex::new(4), U256::from(0xbb))],
2125 )),
2126 ])
2127 }
2128
2129 #[test]
2130 fn bal_compute_hash_returns_empty_hash_for_empty_bal() {
2131 let bal = Bal::default();
2132
2133 assert_eq!(bal.compute_hash(), EMPTY_BLOCK_ACCESS_LIST_HASH);
2134 }
2135
2136 #[test]
2137 fn bal_compute_hash_matches_free_function_for_non_empty_bal() {
2138 let bal = sample_bal();
2139
2140 assert_eq!(bal.compute_hash(), super::compute_block_access_list_hash(bal.as_slice()));
2141 assert_ne!(bal.compute_hash(), EMPTY_BLOCK_ACCESS_LIST_HASH);
2142 }
2143
2144 #[test]
2145 fn bal_compute_hash_with_buf_clears_reused_buffer() {
2146 let bal = sample_bal();
2147 let mut buf = alloc::vec![0xff; 32];
2148
2149 assert_eq!(bal.compute_hash_with_buf(&mut buf), bal.compute_hash());
2150 assert_eq!(
2151 super::compute_block_access_list_hash_with_buf(bal.as_slice(), &mut buf),
2152 super::compute_block_access_list_hash(bal.as_slice())
2153 );
2154 }
2155
2156 #[test]
2157 fn decoded_bal_from_rlp_bytes_preserves_raw_and_hash() {
2158 let bal = sample_bal();
2159 let raw = Bytes::from(alloy_rlp::encode(&bal));
2160 let decoded = DecodedBal::from_rlp_bytes(raw.clone()).unwrap();
2161
2162 assert_eq!(decoded.as_bal(), &bal);
2163 assert_eq!(decoded.as_raw(), &raw);
2164 assert_eq!(decoded.hash(), bal.compute_hash());
2165 assert_eq!(decoded.hash(), alloy_primitives::keccak256(raw.as_ref()));
2166 assert_eq!(decoded.as_sealed_bal().hash(), bal.compute_hash());
2167 assert_eq!(decoded.as_sealed_bal().inner(), &decoded.as_bal());
2168
2169 let (split_bal, split_raw) = decoded.clone().split();
2170 assert_eq!(split_bal, bal);
2171 assert_eq!(split_raw, raw);
2172
2173 let (split_bal, split_raw, split_hash) = decoded.clone().into_parts();
2174 assert_eq!(split_bal, bal);
2175 assert_eq!(split_raw, raw);
2176 assert_eq!(split_hash, bal.compute_hash());
2177
2178 let sealed = decoded.into_sealed();
2179 assert_eq!(sealed.hash(), bal.compute_hash());
2180 assert_eq!(sealed.inner(), &bal);
2181 }
2182
2183 #[test]
2184 fn decoded_bal_from_rlp_bytes_decodes_generic_inner_type() {
2185 let bal = sample_bal();
2186 let raw = Bytes::from(alloy_rlp::encode(&bal));
2187 let decoded = DecodedBal::from_rlp_bytes_as::<Vec<AccountChanges>>(raw.clone()).unwrap();
2188
2189 assert_eq!(decoded.as_bal().as_slice(), bal.as_slice());
2190 assert_eq!(decoded.as_raw(), &raw);
2191 assert_eq!(decoded.hash(), bal.compute_hash());
2192 }
2193
2194 #[test]
2195 fn decoded_bal_decode_consumes_exact_raw_rlp_item() {
2196 let bal = sample_bal();
2197 let raw = alloy_rlp::encode(&bal);
2198 let mut buf = raw.as_ref();
2199 let decoded = <DecodedBal as alloy_rlp::Decodable>::decode(&mut buf).unwrap();
2200
2201 assert!(buf.is_empty());
2202 assert_eq!(decoded.as_bal(), &bal);
2203 assert_eq!(decoded.as_raw().as_ref(), raw.as_slice());
2204 assert_eq!(alloy_rlp::encode(&decoded), raw);
2205 }
2206
2207 #[test]
2208 fn raw_bal_rlp_roundtrip_preserves_raw_item() {
2209 let bal = sample_bal();
2210 let raw = alloy_rlp::encode(&bal);
2211 let mut buf = raw.as_ref();
2212 let raw_bal = <RawBal as alloy_rlp::Decodable>::decode(&mut buf).unwrap();
2213
2214 assert!(buf.is_empty());
2215 assert_eq!(raw_bal.as_raw().as_ref(), raw.as_slice());
2216 assert_eq!(alloy_rlp::encode(&raw_bal), raw);
2217 assert_eq!(raw_bal.hash(), bal.compute_hash());
2218 }
2219
2220 #[test]
2221 fn raw_or_decoded_bal_try_into_decoded_decodes_raw() {
2222 let bal = sample_bal();
2223 let raw = Bytes::from(alloy_rlp::encode(&bal));
2224 let decoded = RawOrDecodedBal::<Bal>::raw(raw.clone()).try_into_decoded().unwrap();
2225
2226 assert_eq!(decoded.as_bal(), &bal);
2227 assert_eq!(decoded.as_raw(), &raw);
2228 assert_eq!(decoded.hash(), bal.compute_hash());
2229 }
2230
2231 #[test]
2232 fn raw_or_decoded_bal_try_into_decoded_reuses_decoded() {
2233 let bal = sample_bal();
2234 let raw = Bytes::from(alloy_rlp::encode(&bal));
2235 let decoded = DecodedBal::new(bal.clone(), raw.clone());
2236 let decoded = RawOrDecodedBal::decoded(decoded).try_into_decoded().unwrap();
2237
2238 assert_eq!(decoded.as_bal(), &bal);
2239 assert_eq!(decoded.as_raw(), &raw);
2240 assert_eq!(decoded.hash(), bal.compute_hash());
2241 }
2242
2243 #[test]
2244 fn raw_or_decoded_bal_rlp_encodes_raw_bytes() {
2245 let bal = sample_bal();
2246 let raw = alloy_rlp::encode(&bal);
2247 let raw_bal = RawOrDecodedBal::<Bal>::raw(Bytes::from(raw.clone()));
2248 let decoded_bal = RawOrDecodedBal::decoded(DecodedBal::new(bal, Bytes::from(raw.clone())));
2249
2250 assert_eq!(alloy_rlp::encode(&raw_bal), raw);
2251 assert_eq!(alloy_rlp::encode(&decoded_bal), raw);
2252 }
2253
2254 #[test]
2255 fn raw_or_decoded_bal_decode_preserves_raw_rlp_item() {
2256 let bal = sample_bal();
2257 let raw = alloy_rlp::encode(&bal);
2258 let mut buf = raw.as_ref();
2259 let decoded = <RawOrDecodedBal as alloy_rlp::Decodable>::decode(&mut buf).unwrap();
2260
2261 assert!(buf.is_empty());
2262 assert!(decoded.is_raw());
2263 assert_eq!(decoded.as_raw().as_ref(), raw.as_slice());
2264 assert_eq!(alloy_rlp::encode(&decoded), raw);
2265
2266 let decoded = decoded.try_into_decoded().unwrap();
2267 assert_eq!(decoded.as_bal(), &bal);
2268 }
2269}