axiom_circuit/subquery/
header.rs

1use anyhow::{bail, Result};
2use axiom_codec::{
3    special_values::{
4        HEADER_EXTRA_DATA_LEN_FIELD_IDX, HEADER_HASH_FIELD_IDX, HEADER_HEADER_SIZE_FIELD_IDX,
5        HEADER_LOGS_BLOOM_FIELD_IDX_OFFSET,
6    },
7    types::native::{AnySubquery, HeaderSubquery},
8};
9use axiom_query::axiom_eth::{halo2_base::AssignedValue, Field};
10use ethers::{
11    providers::{JsonRpcClient, Middleware, Provider},
12    types::{BigEndianHash, BlockId, H256},
13};
14use num_derive::FromPrimitive;
15use num_traits::FromPrimitive;
16use tokio::runtime::Runtime;
17
18use super::{caller::FetchSubquery, types::AssignedHeaderSubquery, utils::pad_to_bytes32};
19use crate::impl_fr_from;
20
21#[derive(FromPrimitive, Clone)]
22pub enum HeaderField {
23    ParentHash,
24    Sha3Uncles,
25    Miner,
26    StateRoot,
27    TransactionsRoot,
28    ReceiptsRoot,
29    LogsBloom,
30    Difficulty,
31    Number,
32    GasLimit,
33    GasUsed,
34    Timestamp,
35    ExtraData,
36    MixHash,
37    Nonce,
38    BaseFeePerGas,
39    WithdrawalsRoot,
40    Hash = HEADER_HASH_FIELD_IDX as isize,
41    Size = HEADER_HEADER_SIZE_FIELD_IDX as isize,
42    ExtraDataLen = HEADER_EXTRA_DATA_LEN_FIELD_IDX as isize,
43}
44impl_fr_from!(HeaderField);
45
46pub async fn get_header_field_value<P: JsonRpcClient>(
47    provider: &Provider<P>,
48    query: HeaderSubquery,
49) -> Result<H256> {
50    let block_id = BlockId::from(query.block_number as u64);
51    let block = provider.get_block(block_id).await?;
52    if block.is_none() {
53        bail!("Block does not exist")
54    }
55    let block = block.unwrap();
56
57    let field_idx = query.field_idx as usize;
58
59    if (HEADER_LOGS_BLOOM_FIELD_IDX_OFFSET..HEADER_LOGS_BLOOM_FIELD_IDX_OFFSET + 8)
60        .contains(&field_idx)
61    {
62        let bloom = block.logs_bloom.unwrap().to_fixed_bytes();
63        let log_idx = (field_idx - HEADER_LOGS_BLOOM_FIELD_IDX_OFFSET) * 32;
64        let bloom_bytes = &bloom[log_idx..log_idx + 32];
65        return Ok(H256::from_slice(bloom_bytes));
66    }
67    let header_field_idx = HeaderField::from_usize(field_idx).expect("Invalid field index");
68    let val = match header_field_idx {
69        HeaderField::ParentHash => block.parent_hash,
70        HeaderField::Sha3Uncles => block.uncles_hash,
71        HeaderField::Miner => H256::from_slice(block.author.unwrap().as_bytes()),
72        HeaderField::StateRoot => block.state_root,
73        HeaderField::TransactionsRoot => block.transactions_root,
74        HeaderField::ReceiptsRoot => block.receipts_root,
75        HeaderField::LogsBloom => {
76            let logs_bloom = block.logs_bloom.unwrap();
77            H256::from(pad_to_bytes32(logs_bloom.as_fixed_bytes()))
78        }
79        HeaderField::Difficulty => H256::from_uint(&block.difficulty),
80        HeaderField::Number => H256::from_low_u64_be(block.number.unwrap().as_u64()),
81        HeaderField::GasLimit => H256::from_uint(&block.gas_limit),
82        HeaderField::GasUsed => H256::from_uint(&block.gas_used),
83        HeaderField::Timestamp => H256::from_uint(&block.timestamp),
84        HeaderField::ExtraData => {
85            let extra_data = block.extra_data;
86            H256::from(pad_to_bytes32(&extra_data))
87        }
88        HeaderField::MixHash => block.mix_hash.unwrap(),
89        HeaderField::Nonce => H256::from_slice(&block.nonce.unwrap().to_fixed_bytes()),
90        HeaderField::BaseFeePerGas => H256::from_uint(&block.base_fee_per_gas.unwrap()),
91        HeaderField::WithdrawalsRoot => block.withdrawals_root.unwrap(),
92        HeaderField::Hash => block.hash.unwrap(),
93        HeaderField::Size => H256::from_uint(&block.size.unwrap()),
94        HeaderField::ExtraDataLen => H256::from_low_u64_be(block.extra_data.len() as u64),
95    };
96
97    Ok(val)
98}
99
100impl<F: Field> FetchSubquery<F> for AssignedHeaderSubquery<F> {
101    fn fetch<P: JsonRpcClient>(&self, p: &Provider<P>) -> Result<H256> {
102        let rt = Runtime::new()?;
103        let val = rt.block_on(get_header_field_value(p, (*self).into()))?;
104        Ok(val)
105    }
106
107    fn any_subquery(&self) -> AnySubquery {
108        AnySubquery::Header((*self).into())
109    }
110
111    fn flatten(&self) -> Vec<AssignedValue<F>> {
112        vec![self.block_number, self.field_idx]
113    }
114}