axiom_circuit/subquery/
account.rs1use anyhow::Result;
2use axiom_codec::types::native::{AccountSubquery, AnySubquery};
3use axiom_query::axiom_eth::{halo2_base::AssignedValue, Field};
4use ethers::{
5 providers::{JsonRpcClient, Middleware, Provider},
6 types::{BigEndianHash, BlockId, H256, U256},
7};
8use num_derive::FromPrimitive;
9use num_traits::FromPrimitive;
10use tokio::runtime::Runtime;
11
12use super::{caller::FetchSubquery, types::AssignedAccountSubquery};
13use crate::impl_fr_from;
14
15#[derive(FromPrimitive, Copy, Clone)]
16pub enum AccountField {
17 Nonce,
18 Balance,
19 StorageHash,
20 CodeHash,
21}
22impl_fr_from!(AccountField);
23
24pub async fn get_account_field_value<P: JsonRpcClient>(
25 provider: &Provider<P>,
26 query: AccountSubquery,
27) -> Result<H256> {
28 let block_id = Some(BlockId::from(query.block_number as u64));
29
30 let account_field = AccountField::from_u32(query.field_idx).expect("Invalid field index");
31 let val = match account_field {
32 AccountField::Nonce => {
33 let nonce = provider.get_transaction_count(query.addr, block_id).await;
34 if nonce.is_err() {
35 return Ok(get_nonexistent_account_field_value(
36 query.field_idx as usize,
37 ));
38 }
39 H256::from_uint(&nonce.unwrap())
40 }
41 AccountField::Balance => {
42 let balance = provider.get_balance(query.addr, block_id).await;
43 if balance.is_err() {
44 return Ok(get_nonexistent_account_field_value(
45 query.field_idx as usize,
46 ));
47 }
48 H256::from_uint(&balance.unwrap())
49 }
50 AccountField::StorageHash => {
51 let proof = provider.get_proof(query.addr, vec![], block_id).await;
52 if proof.is_err() {
53 return Ok(get_nonexistent_account_field_value(
54 query.field_idx as usize,
55 ));
56 }
57 proof.unwrap().storage_hash
58 }
59 AccountField::CodeHash => {
60 let proof = provider.get_proof(query.addr, vec![], block_id).await;
61 if proof.is_err() {
62 return Ok(get_nonexistent_account_field_value(
63 query.field_idx as usize,
64 ));
65 }
66 proof.unwrap().code_hash
67 }
68 };
69
70 Ok(val)
71}
72
73impl<F: Field> FetchSubquery<F> for AssignedAccountSubquery<F> {
74 fn fetch<P: JsonRpcClient>(&self, p: &Provider<P>) -> Result<H256> {
75 let rt = Runtime::new()?;
76 let res = rt.block_on(get_account_field_value(p, (*self).into()))?;
77 Ok(res)
78 }
79
80 fn any_subquery(&self) -> AnySubquery {
81 AnySubquery::Account((*self).into())
82 }
83
84 fn flatten(&self) -> Vec<AssignedValue<F>> {
85 vec![self.block_number, self.addr, self.field_idx]
86 }
87}
88
89fn get_nonexistent_account_field_value(field_idx: usize) -> H256 {
90 let account_field = AccountField::from_usize(field_idx).expect("Invalid field index");
91 match account_field {
92 AccountField::Nonce => H256::from_uint(&U256::from(0)),
93 AccountField::Balance => H256::from_uint(&U256::from(0)),
94 AccountField::StorageHash => H256::from_uint(
95 &U256::from_dec_str(
96 "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
97 )
98 .unwrap(),
99 ),
100 AccountField::CodeHash => H256::from_uint(&U256::from(0)),
101 }
102}