1use serde::{Deserialize, Serialize};
2use yevm_base::{Acc, Int};
3use yevm_misc::buf::Buf;
4
5use crate::{
6 Result,
7 call::{Block, Head},
8 evm::Fetch,
9 state::{Account, State},
10};
11
12#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
13#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
14pub trait Chain {
15 async fn get(&self, acc: &Acc, key: &Int) -> eyre::Result<Int>;
16 async fn acc(&self, acc: &Acc) -> eyre::Result<Account>;
17 async fn code(&self, acc: &Acc) -> eyre::Result<(Buf, Int)>;
18 async fn nonce(&self, acc: &Acc) -> eyre::Result<u64>;
19 async fn balance(&self, acc: &Acc) -> eyre::Result<Int>;
20 async fn head(&self, number: u64) -> eyre::Result<Head>;
21 async fn block(&self, number: u64) -> eyre::Result<Block>;
22 async fn chain_id(&self) -> eyre::Result<u64>;
23}
24
25#[allow(clippy::large_enum_variant)] #[derive(Clone, Debug, Deserialize, Serialize)]
27pub enum Fetched {
28 Account(Acc, Account),
29 State(Acc, Int, Int),
30 Hash(u64, Int),
31 Block(Block),
32 ChainId(u64),
33}
34
35pub async fn fetch(f: Fetch, state: &mut impl State, chain: &impl Chain) -> Result<()> {
36 match f {
37 Fetch::Account(acc) | Fetch::Balance(acc) | Fetch::Nonce(acc) | Fetch::Code(acc) => {
38 if state.is_offline() {
39 let next = state.next_fetched();
40 let Some(Fetched::Account(_, account)) = next else {
41 return Err(
42 eyre::eyre!("Offline fetch: expected account but got {next:?}").into(),
43 );
44 };
45 state.merge(&acc, account.clone());
46 } else {
47 let account = chain.acc(&acc).await?;
48 state.merge(&acc, account.clone());
49 state.save_fetched(Fetched::Account(acc, account));
50 }
51 Ok(())
52 }
53 Fetch::BlockHash(number) => {
54 if state.is_offline() {
55 let next = state.next_fetched();
56 let Some(Fetched::Hash(number, hash)) = next else {
57 return Err(
58 eyre::eyre!("Offline fetch: expected block hash but got {next:?}").into(),
59 );
60 };
61 state.hash(number, hash);
62 } else {
63 let hash = chain
64 .head(number)
65 .await
66 .map(|head| head.hash)
67 .unwrap_or(Int::ZERO);
68 state.hash(number, hash);
69 state.save_fetched(Fetched::Hash(number, hash));
70 }
71 Ok(())
72 }
73 Fetch::StateCell(acc, key) => {
74 if state.is_offline() {
75 let next = state.next_fetched();
76 let Some(Fetched::State(_, _, val)) = next else {
77 return Err(
78 eyre::eyre!("Offline fetch: expected state cell but got {next:?}").into(),
79 );
80 };
81 state.init(&acc, &key, val);
82 } else {
83 let val = chain.get(&acc, &key).await?;
84 state.init(&acc, &key, val);
85 state.save_fetched(Fetched::State(acc, key, val));
86 }
87 Ok(())
88 }
89 }
90}