kabu_types_entities/
required_state.rs1use alloy_network::Network;
2use alloy_primitives::{Address, BlockNumber, Bytes, U256};
3use alloy_provider::Provider;
4use alloy_rpc_types::{BlockId, BlockNumberOrTag};
5use alloy_rpc_types_trace::geth::AccountState;
6use eyre::{eyre, Result};
7use std::collections::BTreeMap;
8use std::fmt::Debug;
9use std::marker::PhantomData;
10use tracing::{error, trace};
11
12use kabu_node_debug_provider::DebugProviderExt;
13use kabu_types_blockchain::{debug_trace_call_pre_state, GethStateUpdate, GethStateUpdateVec, KabuDataTypesEVM};
14use kabu_types_blockchain::{KabuDataTypes, KabuDataTypesEthereum, KabuTransactionRequest};
15
16#[derive(Clone, Debug, Default)]
17pub struct RequiredState {
18 calls: Vec<(Address, Bytes)>,
19 slots: Vec<(Address, U256)>,
20 empty_slots: Vec<(Address, U256)>,
21}
22
23impl RequiredState {
24 pub fn new() -> Self {
25 Self::default()
26 }
27
28 pub fn add_call<T: Into<Bytes>, A: Into<Address>>(&mut self, to: A, call_data: T) -> &mut Self {
29 self.calls.push((to.into(), call_data.into()));
30 self
31 }
32 pub fn add_slot<A: Into<Address>>(&mut self, address: A, slot: U256) -> &mut Self {
33 self.slots.push((address.into(), slot));
34 self
35 }
36
37 pub fn add_empty_slot<A: Into<Address>>(&mut self, address: A, slot: U256) -> &mut Self {
38 self.empty_slots.push((address.into(), slot));
39 self
40 }
41
42 pub fn add_empty_slot_range<A: Into<Address> + Clone>(&mut self, address: A, start_slot: U256, size: usize) -> &mut Self {
43 let mut cur_slot = start_slot;
44 for _ in 0..size {
45 self.add_empty_slot(address.clone(), cur_slot);
46 cur_slot += U256::from(1);
47 }
48 self
49 }
50
51 pub fn add_slot_range<A: Into<Address> + Clone>(&mut self, address: A, start_slot: U256, size: usize) -> &mut Self {
52 let mut cur_slot = start_slot;
53 for _ in 0..size {
54 self.add_slot(address.clone(), cur_slot);
55 cur_slot += U256::from(1);
56 }
57 self
58 }
59}
60
61pub struct RequiredStateReader<LDT: KabuDataTypes = KabuDataTypesEthereum> {
62 _ldt: PhantomData<LDT>,
63}
64
65impl<LDT> RequiredStateReader<LDT>
66where
67 LDT: KabuDataTypesEVM,
68{
69 pub async fn fetch_calls_and_slots<
70 N: Network<TransactionRequest = LDT::TransactionRequest>,
71 C: DebugProviderExt<N> + Provider<N> + Clone + 'static,
72 >(
73 client: C,
74 required_state: RequiredState,
75 block_number: Option<BlockNumber>,
76 ) -> Result<LDT::StateUpdate> {
77 let block_id = if block_number.is_none() {
78 BlockId::Number(BlockNumberOrTag::Latest)
79 } else {
80 BlockId::Number(BlockNumberOrTag::Number(block_number.unwrap_or_default()))
81 };
82
83 let mut ret: GethStateUpdate = GethStateUpdate::new();
84 for req in required_state.calls.into_iter() {
85 let to: Address = req.0;
86 let req: LDT::TransactionRequest = LDT::TransactionRequest::build_call(to, req.1);
87
88 let call_result = debug_trace_call_pre_state(client.clone(), req, block_id, None).await;
89 trace!("trace_call_result: {:?}", call_result);
90 match call_result {
91 Ok(update) => {
92 for (address, account_state) in update.into_iter() {
93 let entry = ret.entry(address).or_insert(account_state.clone());
94 for (slot, value) in account_state.storage.clone().into_iter() {
95 entry.storage.insert(slot, value);
96 trace!(%address, %slot, %value, "Inserting storage");
97 }
98 }
99 }
100 Err(e) => {
101 error!("Contract call failed {} {}", to, e);
102 return Err(eyre!("CONTRACT_CALL_FAILED"));
103 }
104 }
105 }
106 for (address, slot) in required_state.slots.into_iter() {
107 let value_result = client.get_storage_at(address, slot).block_id(block_id).await;
108 trace!("get_storage_at_result {} slot {} : {:?}", address, slot, value_result);
109 match value_result {
110 Ok(value) => {
111 let entry = ret.entry(address).or_default();
112 entry.storage.insert(slot.into(), value.into());
113 }
114 Err(e) => {
115 error!("{}", e)
116 }
117 }
118 }
119
120 for (address, slot) in required_state.empty_slots.into_iter() {
121 let value = U256::ZERO;
122
123 let entry = ret.entry(address).or_default();
124 entry.storage.insert(slot.into(), value.into());
125 }
126
127 Ok(ret)
128 }
129}
130
131pub fn accounts_len(state: &BTreeMap<Address, AccountState>) -> (usize, usize) {
132 let accounts = state.len();
133 let storage = state.values().map(|item| item.storage.clone().len()).sum();
134 (accounts, storage)
135}
136
137pub fn accounts_vec_len(state: &GethStateUpdateVec) -> usize {
138 state.iter().map(|item| accounts_len(item).0).sum()
139}
140
141pub fn storage_vec_len(state: &GethStateUpdateVec) -> usize {
142 state.iter().map(|item| accounts_len(item).1).sum()
143}