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 let mut buf = Vec::new();
18 alloy_rlp::encode_list(bal, &mut buf);
19 alloy_primitives::keccak256(&buf)
20}
21
22pub fn total_bal_items(bal: &[AccountChanges]) -> u64 {
25 let mut bal_items: u64 = 0;
26
27 for account in bal {
28 bal_items += 1;
30
31 let mut unique_slots = alloy_primitives::map::HashSet::new();
33
34 for change in account.storage_changes() {
35 unique_slots.insert(change.slot);
36 }
37
38 for slot in account.storage_reads() {
39 unique_slots.insert(*slot);
40 }
41
42 bal_items += unique_slots.len() as u64;
44 }
45 bal_items
46}
47
48pub mod bal {
50 use super::OnceLock;
51 use crate::{
52 BlockAccessListGasError, BlockAccessListHashMismatch, account_changes::AccountChanges,
53 diff::BalDiff,
54 };
55 use alloc::vec::{IntoIter, Vec};
56 use alloy_primitives::{B256, Bytes};
57 use core::{
58 ops::{Deref, Index},
59 slice::Iter,
60 };
61
62 #[derive(Clone, Debug, Default, PartialEq, Eq)]
68 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
69 #[cfg_attr(
70 feature = "rlp",
71 derive(alloy_rlp::RlpEncodableWrapper, alloy_rlp::RlpDecodableWrapper)
72 )]
73 #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
74 #[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
75 pub struct Bal(Vec<AccountChanges>);
76
77 impl From<Bal> for Vec<AccountChanges> {
78 #[inline]
79 fn from(this: Bal) -> Self {
80 this.0
81 }
82 }
83
84 impl From<Vec<AccountChanges>> for Bal {
85 #[inline]
86 fn from(list: Vec<AccountChanges>) -> Self {
87 Self(list)
88 }
89 }
90
91 #[cfg(feature = "rlp")]
92 impl alloy_primitives::Sealable for Bal {
93 fn hash_slow(&self) -> alloy_primitives::B256 {
94 self.compute_hash()
95 }
96 }
97
98 impl Deref for Bal {
99 type Target = [AccountChanges];
100
101 #[inline]
102 fn deref(&self) -> &Self::Target {
103 self.as_slice()
104 }
105 }
106
107 impl IntoIterator for Bal {
108 type Item = AccountChanges;
109 type IntoIter = IntoIter<AccountChanges>;
110
111 #[inline]
112 fn into_iter(self) -> Self::IntoIter {
113 self.0.into_iter()
114 }
115 }
116
117 impl<'a> IntoIterator for &'a Bal {
118 type Item = &'a AccountChanges;
119 type IntoIter = Iter<'a, AccountChanges>;
120
121 #[inline]
122 fn into_iter(self) -> Self::IntoIter {
123 self.iter()
124 }
125 }
126
127 impl FromIterator<AccountChanges> for Bal {
128 fn from_iter<I: IntoIterator<Item = AccountChanges>>(iter: I) -> Self {
129 Self(iter.into_iter().collect())
130 }
131 }
132
133 impl<I> Index<I> for Bal
134 where
135 I: core::slice::SliceIndex<[AccountChanges]>,
136 {
137 type Output = I::Output;
138
139 #[inline]
140 fn index(&self, index: I) -> &Self::Output {
141 &self.0[index]
142 }
143 }
144
145 impl Bal {
146 #[inline]
148 pub const fn new(account_changes: Vec<AccountChanges>) -> Self {
149 Self(account_changes)
150 }
151
152 #[inline]
154 pub fn push(&mut self, account_changes: AccountChanges) {
155 self.0.push(account_changes)
156 }
157
158 #[inline]
160 pub const fn is_empty(&self) -> bool {
161 self.0.is_empty()
162 }
163
164 #[inline]
166 pub const fn len(&self) -> usize {
167 self.0.len()
168 }
169
170 #[inline]
172 pub fn iter(&self) -> Iter<'_, AccountChanges> {
173 self.0.iter()
174 }
175
176 #[inline]
178 pub const fn as_slice(&self) -> &[AccountChanges] {
179 self.0.as_slice()
180 }
181
182 pub fn diff(&self, other: &[AccountChanges]) -> BalDiff {
184 BalDiff::between(self.as_slice(), other)
185 }
186
187 #[inline]
189 pub fn into_inner(self) -> Vec<AccountChanges> {
190 self.0
191 }
192
193 pub fn sort(&mut self) {
212 self.0.sort_unstable_by_key(|account| account.address);
213
214 for account in &mut self.0 {
215 account.sort();
216 }
217 }
218
219 #[inline]
221 pub const fn account_count(&self) -> usize {
222 self.0.len()
223 }
224
225 pub fn total_storage_changes(&self) -> usize {
227 self.0.iter().map(|a| a.storage_changes.len()).sum()
228 }
229
230 pub fn total_storage_reads(&self) -> usize {
232 self.0.iter().map(|a| a.storage_reads.len()).sum()
233 }
234
235 pub fn total_slots(&self) -> usize {
237 self.0.iter().map(|a| a.storage_changes.len() + a.storage_reads.len()).sum()
238 }
239
240 pub fn total_balance_changes(&self) -> usize {
242 self.0.iter().map(|a| a.balance_changes.len()).sum()
243 }
244
245 pub fn total_nonce_changes(&self) -> usize {
247 self.0.iter().map(|a| a.nonce_changes.len()).sum()
248 }
249
250 pub fn total_code_changes(&self) -> usize {
252 self.0.iter().map(|a| a.code_changes.len()).sum()
253 }
254
255 pub fn change_counts(&self) -> BalChangeCounts {
257 let mut counts = BalChangeCounts::default();
258 for account in &self.0 {
259 counts.accounts += 1;
260 counts.storage += account.storage_changes.len();
261 counts.balance += account.balance_changes.len();
262 counts.nonce += account.nonce_changes.len();
263 counts.code += account.code_changes.len();
264 }
265 counts
266 }
267
268 pub fn total_bal_items(&self) -> u64 {
271 super::total_bal_items(&self.0)
272 }
273
274 pub fn validate_gas_limit(&self, gas_limit: u64) -> Result<(), BlockAccessListGasError> {
279 let items = self.total_bal_items();
280 if items > gas_limit / crate::constants::ITEM_COST as u64 {
281 return Err(BlockAccessListGasError::new(items, gas_limit));
282 }
283 Ok(())
284 }
285
286 #[cfg(feature = "rlp")]
288 pub fn compute_hash(&self) -> alloy_primitives::B256 {
289 if self.0.is_empty() {
290 return crate::constants::EMPTY_BLOCK_ACCESS_LIST_HASH;
291 }
292 super::compute_block_access_list_hash(&self.0)
293 }
294 }
295
296 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
298 pub struct BalChangeCounts {
299 pub accounts: usize,
301 pub storage: usize,
303 pub balance: usize,
305 pub nonce: usize,
307 pub code: usize,
309 }
310
311 #[derive(Clone, Debug)]
313 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
314 #[cfg_attr(feature = "serde", serde(transparent))]
315 pub struct RawBal {
316 raw: Bytes,
318 #[cfg_attr(feature = "serde", serde(skip, default))]
320 hash: OnceLock<B256>,
321 }
322
323 impl PartialEq for RawBal {
324 #[inline]
325 fn eq(&self, other: &Self) -> bool {
326 self.raw == other.raw
327 }
328 }
329
330 impl Eq for RawBal {}
331
332 impl From<Bytes> for RawBal {
333 #[inline]
334 fn from(raw: Bytes) -> Self {
335 Self::new(raw)
336 }
337 }
338
339 impl RawBal {
340 #[inline]
342 pub const fn new(raw: Bytes) -> Self {
343 Self { raw, hash: OnceLock::new() }
344 }
345
346 #[inline]
351 pub fn new_unchecked(raw: Bytes, hash: B256) -> Self {
352 let this = Self::new(raw);
353 #[allow(clippy::useless_conversion)]
354 let _ = this.hash.get_or_init(|| hash.into());
355 this
356 }
357
358 #[inline]
360 pub const fn as_raw(&self) -> &Bytes {
361 &self.raw
362 }
363
364 #[inline]
366 pub fn into_raw(self) -> Bytes {
367 self.raw
368 }
369
370 #[inline]
372 pub fn into_parts(self) -> (Bytes, B256) {
373 let hash = self.hash();
374 (self.raw, hash)
375 }
376
377 #[inline]
379 pub fn ensure_hash(&self, expected: B256) -> Result<(), BlockAccessListHashMismatch> {
380 let computed = self.hash();
381 if computed == expected {
382 Ok(())
383 } else {
384 Err(BlockAccessListHashMismatch::new(computed, expected))
385 }
386 }
387
388 #[inline]
392 pub fn hash(&self) -> B256 {
393 #[allow(clippy::useless_conversion)]
394 *self.hash.get_or_init(|| alloy_primitives::keccak256(self.raw.as_ref()).into())
395 }
396 }
397
398 #[cfg(feature = "rlp")]
399 impl alloy_rlp::Encodable for RawBal {
400 #[inline]
401 fn encode(&self, out: &mut dyn alloy_rlp::BufMut) {
402 out.put_slice(&self.raw);
403 }
404
405 #[inline]
406 fn length(&self) -> usize {
407 self.raw.len()
408 }
409 }
410
411 #[cfg(feature = "rlp")]
412 impl alloy_rlp::Decodable for RawBal {
413 #[inline]
414 fn decode(buf: &mut &[u8]) -> Result<Self, alloy_rlp::Error> {
415 let original = *buf;
416 let header = alloy_rlp::Header::decode(buf)?;
417 let header_len = original.len() - buf.len();
418 let raw_len = header_len + header.payload_length;
419 let raw = Bytes::copy_from_slice(&original[..raw_len]);
420 *buf = &original[raw_len..];
421 Ok(Self::new(raw))
422 }
423 }
424
425 #[derive(Clone, Debug)]
430 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
431 pub struct DecodedBal<T = Bal> {
432 decoded: T,
434 raw: RawBal,
436 }
437
438 impl<T: PartialEq> PartialEq for DecodedBal<T> {
439 #[inline]
440 fn eq(&self, other: &Self) -> bool {
441 self.decoded == other.decoded && self.raw == other.raw
442 }
443 }
444
445 impl<T: Eq> Eq for DecodedBal<T> {}
446
447 impl<T> DecodedBal<T> {
448 #[inline]
450 pub const fn new(decoded: T, raw: Bytes) -> Self {
451 Self { decoded, raw: RawBal::new(raw) }
452 }
453
454 #[inline]
459 pub fn new_unchecked(decoded: T, raw: Bytes, hash: B256) -> Self {
460 Self { decoded, raw: RawBal::new_unchecked(raw, hash) }
461 }
462
463 #[inline]
465 pub const fn with_raw_bal(decoded: T, raw: RawBal) -> Self {
466 Self { decoded, raw }
467 }
468
469 #[inline]
471 pub const fn as_bal(&self) -> &T {
472 &self.decoded
473 }
474
475 #[inline]
477 pub const fn as_raw(&self) -> &Bytes {
478 self.raw.as_raw()
479 }
480
481 #[inline]
483 pub const fn as_raw_bal(&self) -> &RawBal {
484 &self.raw
485 }
486
487 #[inline]
489 pub fn split(self) -> (T, Bytes) {
490 (self.decoded, self.raw.into_raw())
491 }
492
493 #[inline]
495 pub fn split_raw_bal(self) -> (T, RawBal) {
496 (self.decoded, self.raw)
497 }
498
499 #[inline]
501 pub fn into_parts(self) -> (T, Bytes, B256) {
502 let hash = self.hash();
503 let (decoded, raw) = self.split();
504 (decoded, raw, hash)
505 }
506
507 #[inline]
512 pub fn ensure_hash(&self, expected: B256) -> Result<(), BlockAccessListHashMismatch> {
513 let computed = self.hash();
514 if computed == expected {
515 Ok(())
516 } else {
517 Err(BlockAccessListHashMismatch::new(computed, expected))
518 }
519 }
520
521 #[inline]
525 pub fn hash(&self) -> B256 {
526 self.raw.hash()
527 }
528
529 #[inline]
531 pub fn convert<U>(self) -> DecodedBal<U>
532 where
533 U: From<T>,
534 {
535 self.map(U::from)
536 }
537
538 #[inline]
540 pub fn try_convert<U>(self) -> Result<DecodedBal<U>, U::Error>
541 where
542 U: TryFrom<T>,
543 {
544 self.try_map(U::try_from)
545 }
546
547 #[inline]
549 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> DecodedBal<U> {
550 let Self { decoded, raw } = self;
551 DecodedBal { decoded: f(decoded), raw }
552 }
553
554 #[inline]
556 pub fn try_map<U, E>(self, f: impl FnOnce(T) -> Result<U, E>) -> Result<DecodedBal<U>, E> {
557 let Self { decoded, raw } = self;
558 Ok(DecodedBal { decoded: f(decoded)?, raw })
559 }
560 }
561
562 #[cfg(feature = "rlp")]
563 impl DecodedBal {
564 #[inline]
566 pub fn from_rlp_bytes(raw: Bytes) -> Result<Self, alloy_rlp::Error> {
567 Self::from_rlp_bytes_as(raw)
568 }
569
570 #[inline]
572 pub fn from_raw_bal(raw: RawBal) -> Result<Self, alloy_rlp::Error> {
573 Self::from_raw_bal_as(raw)
574 }
575
576 #[inline]
578 pub fn from_rlp_bytes_as<T>(raw: Bytes) -> Result<DecodedBal<T>, alloy_rlp::Error>
579 where
580 T: alloy_rlp::Decodable,
581 {
582 Self::from_raw_bal_as(RawBal::new(raw))
583 }
584
585 #[inline]
587 pub fn from_raw_bal_as<T>(raw: RawBal) -> Result<DecodedBal<T>, alloy_rlp::Error>
588 where
589 T: alloy_rlp::Decodable,
590 {
591 let mut slice = raw.as_raw().as_ref();
592 let decoded = T::decode(&mut slice)?;
593 if !slice.is_empty() {
594 return Err(alloy_rlp::Error::UnexpectedLength);
595 }
596 Ok(DecodedBal::with_raw_bal(decoded, raw))
597 }
598 }
599
600 #[cfg(feature = "rlp")]
601 impl<T> DecodedBal<T>
602 where
603 T: alloy_primitives::Sealable,
604 {
605 #[inline]
607 pub fn as_sealed_bal(&self) -> alloy_primitives::Sealed<&T> {
608 alloy_primitives::Sealable::seal_ref_unchecked(&self.decoded, self.hash())
609 }
610
611 #[inline]
613 pub fn into_sealed(self) -> alloy_primitives::Sealed<T> {
614 let seal = self.hash();
615 let (decoded, _) = self.split();
616 alloy_primitives::Sealable::seal_unchecked(decoded, seal)
617 }
618 }
619
620 #[cfg(feature = "rlp")]
621 impl<T> alloy_rlp::Decodable for DecodedBal<T>
622 where
623 T: alloy_rlp::Decodable,
624 {
625 #[inline]
626 fn decode(buf: &mut &[u8]) -> Result<Self, alloy_rlp::Error> {
627 let original = *buf;
628 let decoded = T::decode(buf)?;
629 let consumed = original.len() - buf.len();
630 let raw = Bytes::copy_from_slice(&original[..consumed]);
631 Ok(Self::new(decoded, raw))
632 }
633 }
634
635 #[cfg(feature = "rlp")]
636 impl<T> alloy_rlp::Encodable for DecodedBal<T> {
637 #[inline]
638 fn encode(&self, out: &mut dyn alloy_rlp::BufMut) {
639 alloy_rlp::Encodable::encode(&self.raw, out);
640 }
641
642 #[inline]
643 fn length(&self) -> usize {
644 alloy_rlp::Encodable::length(&self.raw)
645 }
646 }
647
648 #[derive(Clone, Debug, PartialEq, Eq)]
654 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
655 pub enum RawOrDecodedBal<T = Bal> {
656 Raw(RawBal),
658 Decoded(DecodedBal<T>),
660 }
661
662 impl<T> From<Bytes> for RawOrDecodedBal<T> {
663 #[inline]
664 fn from(raw: Bytes) -> Self {
665 Self::Raw(RawBal::new(raw))
666 }
667 }
668
669 impl<T> From<RawBal> for RawOrDecodedBal<T> {
670 #[inline]
671 fn from(raw: RawBal) -> Self {
672 Self::Raw(raw)
673 }
674 }
675
676 impl<T> From<DecodedBal<T>> for RawOrDecodedBal<T> {
677 #[inline]
678 fn from(decoded: DecodedBal<T>) -> Self {
679 Self::Decoded(decoded)
680 }
681 }
682
683 impl<T> RawOrDecodedBal<T> {
684 #[inline]
686 pub const fn raw(raw: Bytes) -> Self {
687 Self::Raw(RawBal::new(raw))
688 }
689
690 #[inline]
695 pub fn raw_unchecked(raw: Bytes, hash: B256) -> Self {
696 Self::Raw(RawBal::new_unchecked(raw, hash))
697 }
698
699 #[inline]
701 pub const fn raw_bal(raw: RawBal) -> Self {
702 Self::Raw(raw)
703 }
704
705 #[inline]
707 pub const fn decoded(decoded: DecodedBal<T>) -> Self {
708 Self::Decoded(decoded)
709 }
710
711 #[inline]
713 pub const fn is_raw(&self) -> bool {
714 matches!(self, Self::Raw(_))
715 }
716
717 #[inline]
719 pub const fn is_decoded(&self) -> bool {
720 matches!(self, Self::Decoded(_))
721 }
722
723 #[inline]
725 pub const fn as_raw(&self) -> &Bytes {
726 match self {
727 Self::Raw(raw) => raw.as_raw(),
728 Self::Decoded(decoded) => decoded.as_raw(),
729 }
730 }
731
732 #[inline]
734 pub const fn as_raw_bal(&self) -> &RawBal {
735 match self {
736 Self::Raw(raw) => raw,
737 Self::Decoded(decoded) => decoded.as_raw_bal(),
738 }
739 }
740
741 #[inline]
743 pub const fn as_decoded(&self) -> Option<&DecodedBal<T>> {
744 match self {
745 Self::Raw(_) => None,
746 Self::Decoded(decoded) => Some(decoded),
747 }
748 }
749
750 #[inline]
752 pub fn into_decoded(self) -> Option<DecodedBal<T>> {
753 match self {
754 Self::Raw(_) => None,
755 Self::Decoded(decoded) => Some(decoded),
756 }
757 }
758
759 #[inline]
761 pub const fn as_bal(&self) -> Option<&T> {
762 match self {
763 Self::Raw(_) => None,
764 Self::Decoded(decoded) => Some(decoded.as_bal()),
765 }
766 }
767
768 #[inline]
770 pub fn into_raw(self) -> Bytes {
771 match self {
772 Self::Raw(raw) => raw.into_raw(),
773 Self::Decoded(decoded) => decoded.split().1,
774 }
775 }
776
777 #[inline]
779 pub fn into_raw_bal(self) -> RawBal {
780 match self {
781 Self::Raw(raw) => raw,
782 Self::Decoded(decoded) => decoded.split_raw_bal().1,
783 }
784 }
785
786 #[inline]
788 pub fn split(self) -> (Option<T>, Bytes) {
789 match self {
790 Self::Raw(raw) => (None, raw.into_raw()),
791 Self::Decoded(decoded) => {
792 let (bal, raw) = decoded.split();
793 (Some(bal), raw)
794 }
795 }
796 }
797
798 #[inline]
800 pub fn split_raw_bal(self) -> (Option<T>, RawBal) {
801 match self {
802 Self::Raw(raw) => (None, raw),
803 Self::Decoded(decoded) => {
804 let (bal, raw) = decoded.split_raw_bal();
805 (Some(bal), raw)
806 }
807 }
808 }
809
810 #[inline]
812 pub fn ensure_hash(&self, expected: B256) -> Result<(), BlockAccessListHashMismatch> {
813 let computed = self.hash();
814 if computed == expected {
815 Ok(())
816 } else {
817 Err(BlockAccessListHashMismatch::new(computed, expected))
818 }
819 }
820
821 #[inline]
823 pub fn hash(&self) -> B256 {
824 match self {
825 Self::Raw(raw) => raw.hash(),
826 Self::Decoded(decoded) => decoded.hash(),
827 }
828 }
829
830 #[inline]
834 pub fn convert<U>(self) -> RawOrDecodedBal<U>
835 where
836 U: From<T>,
837 {
838 self.map(U::from)
839 }
840
841 #[inline]
845 pub fn try_convert<U>(self) -> Result<RawOrDecodedBal<U>, U::Error>
846 where
847 U: TryFrom<T>,
848 {
849 self.try_map(U::try_from)
850 }
851
852 #[inline]
854 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> RawOrDecodedBal<U> {
855 match self {
856 Self::Raw(raw) => RawOrDecodedBal::Raw(raw),
857 Self::Decoded(decoded) => RawOrDecodedBal::Decoded(decoded.map(f)),
858 }
859 }
860
861 #[inline]
863 pub fn try_map<U, E>(
864 self,
865 f: impl FnOnce(T) -> Result<U, E>,
866 ) -> Result<RawOrDecodedBal<U>, E> {
867 match self {
868 Self::Raw(raw) => Ok(RawOrDecodedBal::Raw(raw)),
869 Self::Decoded(decoded) => decoded.try_map(f).map(RawOrDecodedBal::Decoded),
870 }
871 }
872 }
873
874 #[cfg(feature = "rlp")]
875 impl<T> RawOrDecodedBal<T>
876 where
877 T: alloy_rlp::Decodable,
878 {
879 #[inline]
881 pub fn try_into_decoded(self) -> Result<DecodedBal<T>, alloy_rlp::Error> {
882 match self {
883 Self::Raw(raw) => DecodedBal::from_raw_bal_as(raw),
884 Self::Decoded(decoded) => Ok(decoded),
885 }
886 }
887 }
888
889 #[cfg(feature = "rlp")]
890 impl<T> alloy_rlp::Encodable for RawOrDecodedBal<T> {
891 #[inline]
892 fn encode(&self, out: &mut dyn alloy_rlp::BufMut) {
893 out.put_slice(self.as_raw());
894 }
895
896 #[inline]
897 fn length(&self) -> usize {
898 self.as_raw().len()
899 }
900 }
901
902 #[cfg(feature = "rlp")]
903 impl<T> alloy_rlp::Decodable for RawOrDecodedBal<T> {
904 #[inline]
905 fn decode(buf: &mut &[u8]) -> Result<Self, alloy_rlp::Error> {
906 <RawBal as alloy_rlp::Decodable>::decode(buf).map(Self::Raw)
907 }
908 }
909}
910
911#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, thiserror::Error)]
913#[error(
914 "block access list item cost exceeds gas limit: items={items}, max_items={max_items}, gas_limit={gas_limit}"
915)]
916pub struct BlockAccessListGasError {
917 pub items: u64,
919 pub max_items: u64,
921 pub gas_limit: u64,
923}
924
925impl BlockAccessListGasError {
926 #[inline]
928 pub const fn new(items: u64, gas_limit: u64) -> Self {
929 Self { items, max_items: gas_limit / crate::constants::ITEM_COST as u64, gas_limit }
930 }
931}
932
933#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, thiserror::Error)]
935#[error("block access list hash mismatch: computed={computed}, expected={expected}")]
936pub struct BlockAccessListHashMismatch {
937 pub computed: alloy_primitives::B256,
939 pub expected: alloy_primitives::B256,
941}
942
943impl BlockAccessListHashMismatch {
944 #[inline]
946 pub const fn new(computed: alloy_primitives::B256, expected: alloy_primitives::B256) -> Self {
947 Self { computed, expected }
948 }
949}
950
951#[cfg(test)]
952mod hash_tests {
953 use super::bal::{Bal, DecodedBal, RawBal, RawOrDecodedBal};
954 use crate::{
955 AccountChanges, BalanceChange, BlockAccessIndex, CodeChange, NonceChange, SlotChanges,
956 StorageChange, constants::ITEM_COST,
957 };
958 use alloy_primitives::{Address, B256, Bytes, U256};
959
960 #[test]
961 fn decoded_bal_hash_uses_raw_bytes_without_rlp_feature() {
962 let raw = Bytes::from_static(&[0xc0]);
963 let decoded = DecodedBal::new(Bal::default(), raw.clone());
964
965 assert_eq!(decoded.hash(), alloy_primitives::keccak256(raw.as_ref()));
966
967 let (bal, split_raw, split_hash) = decoded.into_parts();
968 assert!(bal.is_empty());
969 assert_eq!(split_raw, raw);
970 assert_eq!(split_hash, alloy_primitives::keccak256(raw.as_ref()));
971 }
972
973 #[test]
974 fn decoded_bal_map_preserves_raw_and_hash() {
975 let raw = Bytes::from_static(&[0xc0]);
976 let decoded = DecodedBal::new(Bal::default(), raw.clone());
977 let hash = decoded.hash();
978
979 let mapped = decoded.map(|bal| bal.len());
980
981 assert_eq!(mapped.as_bal(), &0);
982 assert_eq!(mapped.as_raw(), &raw);
983 assert_eq!(mapped.hash(), hash);
984 }
985
986 #[test]
987 fn decoded_bal_try_map_converts_or_returns_error() {
988 let raw = Bytes::from_static(&[0xc0]);
989 let decoded = DecodedBal::new(Bal::default(), raw.clone());
990
991 let mapped = decoded.try_map(|bal| Ok::<_, core::convert::Infallible>(bal.len())).unwrap();
992
993 assert_eq!(mapped.as_bal(), &0);
994 assert_eq!(mapped.as_raw(), &raw);
995
996 let decoded = DecodedBal::new(Bal::default(), raw);
997 let err = decoded.try_map(|_| Err::<usize, _>("expected error")).unwrap_err();
998
999 assert_eq!(err, "expected error");
1000 }
1001
1002 #[derive(Debug, PartialEq, Eq)]
1003 struct BalLen(usize);
1004
1005 impl From<Bal> for BalLen {
1006 fn from(value: Bal) -> Self {
1007 Self(value.len())
1008 }
1009 }
1010
1011 #[derive(Debug, PartialEq, Eq)]
1012 struct NonEmptyBal(Bal);
1013
1014 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
1015 struct EmptyBal;
1016
1017 impl TryFrom<Bal> for NonEmptyBal {
1018 type Error = EmptyBal;
1019
1020 fn try_from(value: Bal) -> Result<Self, Self::Error> {
1021 if value.is_empty() { Err(EmptyBal) } else { Ok(Self(value)) }
1022 }
1023 }
1024
1025 #[test]
1026 fn decoded_bal_convert_and_try_convert_use_inner_conversions() {
1027 let raw = Bytes::from_static(&[0xc0]);
1028 let converted: DecodedBal<BalLen> = DecodedBal::new(Bal::default(), raw.clone()).convert();
1029
1030 assert_eq!(converted.as_bal(), &BalLen(0));
1031 assert_eq!(converted.as_raw(), &raw);
1032
1033 let err = DecodedBal::new(Bal::default(), raw.clone()).try_convert::<NonEmptyBal>();
1034 assert_eq!(err.unwrap_err(), EmptyBal);
1035
1036 let bal = Bal::new(vec![AccountChanges::new(Address::from([0x11; 20]))]);
1037 let converted = DecodedBal::new(bal, raw).try_convert::<NonEmptyBal>().unwrap();
1038
1039 assert_eq!(converted.as_bal().0.len(), 1);
1040 }
1041
1042 #[test]
1043 fn decoded_bal_ensure_hash_reports_both_hashes() {
1044 let raw = Bytes::from_static(&[0xc0]);
1045 let decoded = DecodedBal::new(Bal::default(), raw.clone());
1046 let computed = alloy_primitives::keccak256(raw.as_ref());
1047 let expected = B256::from([0x11; 32]);
1048
1049 assert_eq!(decoded.ensure_hash(computed), Ok(()));
1050 assert_eq!(
1051 decoded.ensure_hash(expected),
1052 Err(super::BlockAccessListHashMismatch::new(computed, expected))
1053 );
1054 }
1055
1056 #[test]
1057 fn raw_bal_hash_uses_raw_bytes() {
1058 let raw = Bytes::from_static(&[0xc0]);
1059 let raw_bal = RawBal::new(raw.clone());
1060 let computed = alloy_primitives::keccak256(raw.as_ref());
1061 let expected = B256::from([0x11; 32]);
1062
1063 assert_eq!(raw_bal.as_raw(), &raw);
1064 assert_eq!(raw_bal.hash(), computed);
1065 assert_eq!(raw_bal.ensure_hash(computed), Ok(()));
1066 assert_eq!(
1067 raw_bal.ensure_hash(expected),
1068 Err(super::BlockAccessListHashMismatch::new(computed, expected))
1069 );
1070
1071 let (split_raw, split_hash) = raw_bal.into_parts();
1072 assert_eq!(split_raw, raw);
1073 assert_eq!(split_hash, computed);
1074 }
1075
1076 #[test]
1077 fn raw_bal_new_unchecked_uses_supplied_hash() {
1078 let raw = Bytes::from_static(&[0xc0]);
1079 let hash = B256::from([0x11; 32]);
1080 let raw_bal = RawBal::new_unchecked(raw.clone(), hash);
1081
1082 assert_eq!(raw_bal.as_raw(), &raw);
1083 assert_eq!(raw_bal.hash(), hash);
1084 assert_eq!(raw_bal.ensure_hash(hash), Ok(()));
1085
1086 let (split_raw, split_hash) = raw_bal.into_parts();
1087 assert_eq!(split_raw, raw);
1088 assert_eq!(split_hash, hash);
1089 }
1090
1091 #[test]
1092 fn decoded_bal_exposes_raw_bal() {
1093 let raw = Bytes::from_static(&[0xc0]);
1094 let raw_bal = RawBal::new(raw.clone());
1095 let decoded = DecodedBal::with_raw_bal(Bal::default(), raw_bal.clone());
1096
1097 assert_eq!(decoded.as_raw_bal(), &raw_bal);
1098 assert_eq!(decoded.as_raw(), &raw);
1099
1100 let (bal, split_raw_bal) = decoded.split_raw_bal();
1101 assert!(bal.is_empty());
1102 assert_eq!(split_raw_bal, raw_bal);
1103 }
1104
1105 #[test]
1106 fn decoded_bal_new_unchecked_uses_supplied_hash() {
1107 let raw = Bytes::from_static(&[0xc0]);
1108 let hash = B256::from([0x11; 32]);
1109 let decoded = DecodedBal::new_unchecked(Bal::default(), raw.clone(), hash);
1110
1111 assert_eq!(decoded.as_raw(), &raw);
1112 assert_eq!(decoded.hash(), hash);
1113 assert_eq!(decoded.ensure_hash(hash), Ok(()));
1114 }
1115
1116 #[cfg(feature = "serde")]
1117 #[test]
1118 fn decoded_bal_serde_keeps_raw_bytes_field() {
1119 let raw = Bytes::from_static(&[0xc0]);
1120 let decoded = DecodedBal::new(Bal::default(), raw.clone());
1121 let value = serde_json::to_value(&decoded).unwrap();
1122
1123 assert!(value.get("decoded").is_some());
1124 assert_eq!(value.get("raw"), Some(&serde_json::to_value(&raw).unwrap()));
1125 assert!(value.get("hash").is_none());
1126
1127 let decoded = serde_json::from_value::<DecodedBal>(value).unwrap();
1128 assert_eq!(decoded.as_bal(), &Bal::default());
1129 assert_eq!(decoded.as_raw(), &raw);
1130 }
1131
1132 #[test]
1133 fn raw_or_decoded_bal_raw_helpers_use_raw_bytes() {
1134 let raw = Bytes::from_static(&[0xc0]);
1135 let bal = RawOrDecodedBal::<Bal>::raw(raw.clone());
1136 let hash = alloy_primitives::keccak256(raw.as_ref());
1137
1138 assert!(bal.is_raw());
1139 assert!(!bal.is_decoded());
1140 assert_eq!(bal.as_raw(), &raw);
1141 assert_eq!(bal.as_raw_bal().as_raw(), &raw);
1142 assert_eq!(bal.as_decoded(), None);
1143 assert_eq!(bal.as_bal(), None);
1144 assert_eq!(bal.hash(), hash);
1145 assert_eq!(bal.ensure_hash(hash), Ok(()));
1146
1147 let (decoded, split_raw) = bal.clone().split();
1148 assert_eq!(decoded, None);
1149 assert_eq!(split_raw, raw);
1150 let (decoded, split_raw_bal) = bal.clone().split_raw_bal();
1151 assert_eq!(decoded, None);
1152 assert_eq!(split_raw_bal.as_raw(), &raw);
1153 assert_eq!(bal.clone().into_raw_bal().as_raw(), &raw);
1154 assert_eq!(bal.into_raw(), raw);
1155 }
1156
1157 #[test]
1158 fn raw_or_decoded_bal_raw_unchecked_uses_supplied_hash() {
1159 let raw = Bytes::from_static(&[0xc0]);
1160 let hash = B256::from([0x11; 32]);
1161 let bal = RawOrDecodedBal::<Bal>::raw_unchecked(raw.clone(), hash);
1162
1163 assert!(bal.is_raw());
1164 assert_eq!(bal.as_raw(), &raw);
1165 assert_eq!(bal.hash(), hash);
1166 assert_eq!(bal.ensure_hash(hash), Ok(()));
1167 }
1168
1169 #[test]
1170 fn raw_or_decoded_bal_decoded_helpers_use_decoded_bal() {
1171 let raw = Bytes::from_static(&[0xc0]);
1172 let decoded = DecodedBal::new(Bal::default(), raw.clone());
1173 let hash = decoded.hash();
1174 let bal = RawOrDecodedBal::decoded(decoded.clone());
1175
1176 assert!(!bal.is_raw());
1177 assert!(bal.is_decoded());
1178 assert_eq!(bal.as_raw(), &raw);
1179 assert_eq!(bal.as_raw_bal(), decoded.as_raw_bal());
1180 assert_eq!(bal.as_decoded(), Some(&decoded));
1181 assert_eq!(bal.as_bal(), Some(decoded.as_bal()));
1182 assert_eq!(bal.hash(), hash);
1183
1184 let (split_bal, split_raw) = bal.clone().split();
1185 assert_eq!(split_bal, Some(Bal::default()));
1186 assert_eq!(split_raw, raw);
1187 let (split_bal, split_raw_bal) = bal.clone().split_raw_bal();
1188 assert_eq!(split_bal, Some(Bal::default()));
1189 assert_eq!(split_raw_bal.as_raw(), &raw);
1190 assert_eq!(bal.into_decoded(), Some(decoded));
1191 }
1192
1193 #[test]
1194 fn raw_or_decoded_bal_convert_maps_only_decoded_values() {
1195 let raw = Bytes::from_static(&[0xc0]);
1196 let raw_bal: RawOrDecodedBal<Bal> = RawOrDecodedBal::raw(raw.clone());
1197 let converted_raw: RawOrDecodedBal<BalLen> = raw_bal.convert();
1198
1199 assert!(converted_raw.is_raw());
1200 assert_eq!(converted_raw.as_raw(), &raw);
1201 assert_eq!(converted_raw.as_bal(), None);
1202
1203 let decoded = DecodedBal::new(Bal::default(), raw.clone());
1204 let converted_decoded: RawOrDecodedBal<BalLen> =
1205 RawOrDecodedBal::decoded(decoded).convert();
1206
1207 assert!(converted_decoded.is_decoded());
1208 assert_eq!(converted_decoded.as_bal(), Some(&BalLen(0)));
1209 assert_eq!(converted_decoded.as_raw(), &raw);
1210
1211 let err = RawOrDecodedBal::decoded(DecodedBal::new(Bal::default(), raw.clone()))
1212 .try_convert::<NonEmptyBal>();
1213 assert_eq!(err.unwrap_err(), EmptyBal);
1214
1215 let raw_result: Result<RawOrDecodedBal<NonEmptyBal>, EmptyBal> =
1216 RawOrDecodedBal::<Bal>::raw(raw.clone()).try_convert();
1217 let raw_result = raw_result.unwrap();
1218 assert!(raw_result.is_raw());
1219 assert_eq!(raw_result.as_raw(), &raw);
1220 }
1221
1222 #[test]
1223 fn bal_sort_orders_all_eip7928_lists() {
1224 let address_1 = Address::from([0x11; 20]);
1225 let address_2 = Address::from([0x22; 20]);
1226 let mut bal = Bal::new(vec![
1227 AccountChanges {
1228 address: address_2,
1229 storage_changes: vec![
1230 SlotChanges::new(
1231 U256::from(3),
1232 vec![
1233 StorageChange::new(BlockAccessIndex::new(8), U256::from(0x80)),
1234 StorageChange::new(BlockAccessIndex::new(2), U256::from(0x20)),
1235 ],
1236 ),
1237 SlotChanges::new(
1238 U256::from(1),
1239 vec![
1240 StorageChange::new(BlockAccessIndex::new(5), U256::from(0x50)),
1241 StorageChange::new(BlockAccessIndex::new(1), U256::from(0x10)),
1242 ],
1243 ),
1244 ],
1245 storage_reads: vec![U256::from(4), U256::from(2)],
1246 balance_changes: vec![
1247 BalanceChange::new(BlockAccessIndex::new(6), U256::from(600)),
1248 BalanceChange::new(BlockAccessIndex::new(3), U256::from(300)),
1249 ],
1250 nonce_changes: vec![
1251 NonceChange::new(BlockAccessIndex::new(7), 70),
1252 NonceChange::new(BlockAccessIndex::new(4), 40),
1253 ],
1254 code_changes: vec![
1255 CodeChange::new(BlockAccessIndex::new(9), Bytes::from_static(&[0x60, 0x09])),
1256 CodeChange::new(BlockAccessIndex::new(5), Bytes::from_static(&[0x60, 0x05])),
1257 ],
1258 },
1259 AccountChanges {
1260 address: address_1,
1261 storage_changes: vec![
1262 SlotChanges::new(
1263 U256::from(2),
1264 vec![
1265 StorageChange::new(BlockAccessIndex::new(4), U256::from(0x40)),
1266 StorageChange::new(BlockAccessIndex::new(0), U256::from(0x00)),
1267 ],
1268 ),
1269 SlotChanges::new(
1270 U256::from(1),
1271 vec![
1272 StorageChange::new(BlockAccessIndex::new(3), U256::from(0x30)),
1273 StorageChange::new(BlockAccessIndex::new(1), U256::from(0x10)),
1274 ],
1275 ),
1276 ],
1277 storage_reads: vec![U256::from(5), U256::from(3)],
1278 balance_changes: vec![
1279 BalanceChange::new(BlockAccessIndex::new(5), U256::from(500)),
1280 BalanceChange::new(BlockAccessIndex::new(2), U256::from(200)),
1281 ],
1282 nonce_changes: vec![
1283 NonceChange::new(BlockAccessIndex::new(8), 80),
1284 NonceChange::new(BlockAccessIndex::new(1), 10),
1285 ],
1286 code_changes: vec![
1287 CodeChange::new(BlockAccessIndex::new(4), Bytes::from_static(&[0x60, 0x04])),
1288 CodeChange::new(BlockAccessIndex::new(2), Bytes::from_static(&[0x60, 0x02])),
1289 ],
1290 },
1291 ]);
1292
1293 bal.sort();
1294
1295 assert_eq!(bal[0].address, address_1);
1296 assert_eq!(bal[1].address, address_2);
1297
1298 for account in bal.iter() {
1299 assert!(account.storage_changes.windows(2).all(|slots| slots[0].slot <= slots[1].slot));
1300 for slot_changes in &account.storage_changes {
1301 assert!(
1302 slot_changes
1303 .changes
1304 .windows(2)
1305 .all(|changes| changes[0].block_access_index
1306 <= changes[1].block_access_index)
1307 );
1308 }
1309 assert!(account.storage_reads.windows(2).all(|slots| slots[0] <= slots[1]));
1310 assert!(
1311 account
1312 .balance_changes
1313 .windows(2)
1314 .all(|changes| changes[0].block_access_index <= changes[1].block_access_index)
1315 );
1316 assert!(
1317 account
1318 .nonce_changes
1319 .windows(2)
1320 .all(|changes| changes[0].block_access_index <= changes[1].block_access_index)
1321 );
1322 assert!(
1323 account
1324 .code_changes
1325 .windows(2)
1326 .all(|changes| changes[0].block_access_index <= changes[1].block_access_index)
1327 );
1328 }
1329 }
1330
1331 #[test]
1332 fn bal_validate_gas_limit_accepts_exact_item_cost() {
1333 let bal = Bal::new(vec![
1334 AccountChanges::new(Address::from([0x11; 20]))
1335 .with_storage_read(U256::from(1))
1336 .with_storage_change(SlotChanges::new(
1337 U256::from(1),
1338 vec![StorageChange::new(BlockAccessIndex::new(0), U256::from(0xaa))],
1339 )),
1340 ]);
1341
1342 assert_eq!(bal.total_bal_items(), 2);
1343 assert_eq!(bal.validate_gas_limit(2 * ITEM_COST as u64), Ok(()));
1344 }
1345
1346 #[test]
1347 fn bal_validate_gas_limit_rejects_item_cost_above_limit() {
1348 let bal = Bal::new(vec![
1349 AccountChanges::new(Address::from([0x11; 20]))
1350 .with_storage_read(U256::from(1))
1351 .with_storage_read(U256::from(2)),
1352 ]);
1353 let gas_limit = 3 * ITEM_COST as u64 - 1;
1354
1355 assert_eq!(bal.total_bal_items(), 3);
1356 assert_eq!(
1357 bal.validate_gas_limit(gas_limit),
1358 Err(super::BlockAccessListGasError::new(3, gas_limit))
1359 );
1360 }
1361}
1362
1363#[cfg(all(test, feature = "rlp"))]
1364mod tests {
1365 use super::bal::{Bal, DecodedBal, RawBal, RawOrDecodedBal};
1366 use crate::{
1367 AccountChanges, BalanceChange, BlockAccessIndex, CodeChange, NonceChange, SlotChanges,
1368 StorageChange, constants::EMPTY_BLOCK_ACCESS_LIST_HASH,
1369 };
1370 use alloy_primitives::{Address, Bytes, U256};
1371
1372 fn sample_bal() -> Bal {
1373 Bal::new(vec![
1374 AccountChanges::new(Address::from([0x11; 20]))
1375 .with_storage_read(U256::from(0x10))
1376 .with_storage_change(SlotChanges::new(
1377 U256::from(0x01),
1378 vec![StorageChange::new(BlockAccessIndex::new(0), U256::from(0xaa))],
1379 ))
1380 .with_balance_change(BalanceChange::new(
1381 BlockAccessIndex::new(1),
1382 U256::from(1_000),
1383 ))
1384 .with_nonce_change(NonceChange::new(BlockAccessIndex::new(2), 7))
1385 .with_code_change(CodeChange::new(
1386 BlockAccessIndex::new(3),
1387 Bytes::from(vec![0x60, 0x00]),
1388 )),
1389 AccountChanges::new(Address::from([0x22; 20]))
1390 .with_storage_read(U256::from(0x20))
1391 .with_storage_change(SlotChanges::new(
1392 U256::from(0x02),
1393 vec![StorageChange::new(BlockAccessIndex::new(4), U256::from(0xbb))],
1394 )),
1395 ])
1396 }
1397
1398 #[test]
1399 fn bal_compute_hash_returns_empty_hash_for_empty_bal() {
1400 let bal = Bal::default();
1401
1402 assert_eq!(bal.compute_hash(), EMPTY_BLOCK_ACCESS_LIST_HASH);
1403 }
1404
1405 #[test]
1406 fn bal_compute_hash_matches_free_function_for_non_empty_bal() {
1407 let bal = sample_bal();
1408
1409 assert_eq!(bal.compute_hash(), super::compute_block_access_list_hash(bal.as_slice()));
1410 assert_ne!(bal.compute_hash(), EMPTY_BLOCK_ACCESS_LIST_HASH);
1411 }
1412
1413 #[test]
1414 fn decoded_bal_from_rlp_bytes_preserves_raw_and_hash() {
1415 let bal = sample_bal();
1416 let raw = Bytes::from(alloy_rlp::encode(&bal));
1417 let decoded = DecodedBal::from_rlp_bytes(raw.clone()).unwrap();
1418
1419 assert_eq!(decoded.as_bal(), &bal);
1420 assert_eq!(decoded.as_raw(), &raw);
1421 assert_eq!(decoded.hash(), bal.compute_hash());
1422 assert_eq!(decoded.hash(), alloy_primitives::keccak256(raw.as_ref()));
1423 assert_eq!(decoded.as_sealed_bal().hash(), bal.compute_hash());
1424 assert_eq!(decoded.as_sealed_bal().inner(), &decoded.as_bal());
1425
1426 let (split_bal, split_raw) = decoded.clone().split();
1427 assert_eq!(split_bal, bal);
1428 assert_eq!(split_raw, raw);
1429
1430 let (split_bal, split_raw, split_hash) = decoded.clone().into_parts();
1431 assert_eq!(split_bal, bal);
1432 assert_eq!(split_raw, raw);
1433 assert_eq!(split_hash, bal.compute_hash());
1434
1435 let sealed = decoded.into_sealed();
1436 assert_eq!(sealed.hash(), bal.compute_hash());
1437 assert_eq!(sealed.inner(), &bal);
1438 }
1439
1440 #[test]
1441 fn decoded_bal_from_rlp_bytes_decodes_generic_inner_type() {
1442 let bal = sample_bal();
1443 let raw = Bytes::from(alloy_rlp::encode(&bal));
1444 let decoded = DecodedBal::from_rlp_bytes_as::<Vec<AccountChanges>>(raw.clone()).unwrap();
1445
1446 assert_eq!(decoded.as_bal().as_slice(), bal.as_slice());
1447 assert_eq!(decoded.as_raw(), &raw);
1448 assert_eq!(decoded.hash(), bal.compute_hash());
1449 }
1450
1451 #[test]
1452 fn decoded_bal_decode_consumes_exact_raw_rlp_item() {
1453 let bal = sample_bal();
1454 let raw = alloy_rlp::encode(&bal);
1455 let mut buf = raw.as_ref();
1456 let decoded = <DecodedBal as alloy_rlp::Decodable>::decode(&mut buf).unwrap();
1457
1458 assert!(buf.is_empty());
1459 assert_eq!(decoded.as_bal(), &bal);
1460 assert_eq!(decoded.as_raw().as_ref(), raw.as_slice());
1461 assert_eq!(alloy_rlp::encode(&decoded), raw);
1462 }
1463
1464 #[test]
1465 fn raw_bal_rlp_roundtrip_preserves_raw_item() {
1466 let bal = sample_bal();
1467 let raw = alloy_rlp::encode(&bal);
1468 let mut buf = raw.as_ref();
1469 let raw_bal = <RawBal as alloy_rlp::Decodable>::decode(&mut buf).unwrap();
1470
1471 assert!(buf.is_empty());
1472 assert_eq!(raw_bal.as_raw().as_ref(), raw.as_slice());
1473 assert_eq!(alloy_rlp::encode(&raw_bal), raw);
1474 assert_eq!(raw_bal.hash(), bal.compute_hash());
1475 }
1476
1477 #[test]
1478 fn raw_or_decoded_bal_try_into_decoded_decodes_raw() {
1479 let bal = sample_bal();
1480 let raw = Bytes::from(alloy_rlp::encode(&bal));
1481 let decoded = RawOrDecodedBal::<Bal>::raw(raw.clone()).try_into_decoded().unwrap();
1482
1483 assert_eq!(decoded.as_bal(), &bal);
1484 assert_eq!(decoded.as_raw(), &raw);
1485 assert_eq!(decoded.hash(), bal.compute_hash());
1486 }
1487
1488 #[test]
1489 fn raw_or_decoded_bal_try_into_decoded_reuses_decoded() {
1490 let bal = sample_bal();
1491 let raw = Bytes::from(alloy_rlp::encode(&bal));
1492 let decoded = DecodedBal::new(bal.clone(), raw.clone());
1493 let decoded = RawOrDecodedBal::decoded(decoded).try_into_decoded().unwrap();
1494
1495 assert_eq!(decoded.as_bal(), &bal);
1496 assert_eq!(decoded.as_raw(), &raw);
1497 assert_eq!(decoded.hash(), bal.compute_hash());
1498 }
1499
1500 #[test]
1501 fn raw_or_decoded_bal_rlp_encodes_raw_bytes() {
1502 let bal = sample_bal();
1503 let raw = alloy_rlp::encode(&bal);
1504 let raw_bal = RawOrDecodedBal::<Bal>::raw(Bytes::from(raw.clone()));
1505 let decoded_bal = RawOrDecodedBal::decoded(DecodedBal::new(bal, Bytes::from(raw.clone())));
1506
1507 assert_eq!(alloy_rlp::encode(&raw_bal), raw);
1508 assert_eq!(alloy_rlp::encode(&decoded_bal), raw);
1509 }
1510
1511 #[test]
1512 fn raw_or_decoded_bal_decode_preserves_raw_rlp_item() {
1513 let bal = sample_bal();
1514 let raw = alloy_rlp::encode(&bal);
1515 let mut buf = raw.as_ref();
1516 let decoded = <RawOrDecodedBal as alloy_rlp::Decodable>::decode(&mut buf).unwrap();
1517
1518 assert!(buf.is_empty());
1519 assert!(decoded.is_raw());
1520 assert_eq!(decoded.as_raw().as_ref(), raw.as_slice());
1521 assert_eq!(alloy_rlp::encode(&decoded), raw);
1522
1523 let decoded = decoded.try_into_decoded().unwrap();
1524 assert_eq!(decoded.as_bal(), &bal);
1525 }
1526}