1use crate::{
19 AccountChanges, BalanceChange, BlockAccessList, CodeChange, CodecError, NonceChange,
20 SlotChanges, StorageChange,
21};
22use alloy_primitives::{Address, Bytes, U256};
23use serde::Deserialize;
24
25#[derive(Deserialize)]
26#[serde(rename_all = "camelCase", deny_unknown_fields)]
27struct RpcAccount {
28 address: Address,
29 #[serde(default)]
30 storage_changes: Vec<RpcSlot>,
31 #[serde(default)]
32 storage_reads: Vec<U256>,
33 #[serde(default)]
34 balance_changes: Vec<RpcIndexed>,
35 #[serde(default)]
36 nonce_changes: Vec<RpcIndexed>,
37 #[serde(default)]
38 code_changes: Vec<RpcCode>,
39}
40
41#[derive(Deserialize)]
42#[serde(rename_all = "camelCase", deny_unknown_fields)]
43struct RpcSlot {
44 key: U256,
45 changes: Vec<RpcIndexed>,
46}
47
48#[derive(Deserialize)]
49#[serde(deny_unknown_fields)]
50struct RpcIndexed {
51 index: U256,
52 value: U256,
53}
54
55#[derive(Deserialize)]
56#[serde(deny_unknown_fields)]
57struct RpcCode {
58 index: U256,
59 code: Bytes,
60}
61
62fn idx(u: U256) -> Result<u32, CodecError> {
63 u.try_into()
64 .map_err(|_| CodecError::Json(format!("block access index {u} exceeds u32")))
65}
66
67impl BlockAccessList {
68 pub fn from_rpc_json(v: &serde_json::Value) -> Result<Self, CodecError> {
72 let accounts: Vec<RpcAccount> = serde::Deserialize::deserialize(v)
75 .map_err(|e: serde_json::Error| CodecError::Json(e.to_string()))?;
76 let mut out = Vec::with_capacity(accounts.len());
77 for a in accounts {
78 out.push(AccountChanges {
79 address: a.address,
80 storage_changes: a
81 .storage_changes
82 .into_iter()
83 .map(|s| {
84 Ok(SlotChanges {
85 slot: s.key,
86 changes: s
87 .changes
88 .into_iter()
89 .map(|c| {
90 Ok(StorageChange {
91 block_access_index: idx(c.index)?,
92 value: c.value,
93 })
94 })
95 .collect::<Result<_, CodecError>>()?,
96 })
97 })
98 .collect::<Result<_, CodecError>>()?,
99 storage_reads: a.storage_reads,
100 balance_changes: a
101 .balance_changes
102 .into_iter()
103 .map(|c| {
104 Ok(BalanceChange {
105 block_access_index: idx(c.index)?,
106 post_balance: c.value,
107 })
108 })
109 .collect::<Result<_, CodecError>>()?,
110 nonce_changes: a
111 .nonce_changes
112 .into_iter()
113 .map(|c| {
114 Ok(NonceChange {
115 block_access_index: idx(c.index)?,
116 new_nonce: c.value.try_into().map_err(|_| {
117 CodecError::Json(format!("nonce {} exceeds u64", c.value))
118 })?,
119 })
120 })
121 .collect::<Result<_, CodecError>>()?,
122 code_changes: a
123 .code_changes
124 .into_iter()
125 .map(|c| {
126 Ok(CodeChange {
127 block_access_index: idx(c.index)?,
128 new_code: c.code,
129 })
130 })
131 .collect::<Result<_, CodecError>>()?,
132 });
133 }
134 let bal = BlockAccessList { accounts: out };
135 crate::validate::validate(&bal)?;
136 Ok(bal)
137 }
138}