axiom_circuit/subquery/
header.rs1use 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}