axiom_codec/types/
field_elements.rs

1use std::{fmt::Debug, ops::Deref};
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6    constants::{MAX_SOLIDITY_MAPPING_KEYS, MAX_SUBQUERY_INPUTS, MAX_SUBQUERY_OUTPUTS},
7    Field, HiLo,
8};
9
10use super::native::SubqueryType;
11
12pub const SUBQUERY_KEY_LEN: usize = 1 + MAX_SUBQUERY_INPUTS;
13pub const SUBQUERY_RESULT_LEN: usize = SUBQUERY_KEY_LEN + MAX_SUBQUERY_OUTPUTS;
14
15/// Subquery type and data
16#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, Serialize, Deserialize)]
17pub struct SubqueryKey<T>(pub [T; SUBQUERY_KEY_LEN]);
18
19/// Only the output of the subquery. Does not include subquery data.
20#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, Serialize, Deserialize)]
21pub struct SubqueryOutput<T>(pub [T; MAX_SUBQUERY_OUTPUTS]);
22
23impl<T> Deref for SubqueryKey<T> {
24    type Target = [T];
25    fn deref(&self) -> &Self::Target {
26        &self.0
27    }
28}
29
30impl<T> Deref for SubqueryOutput<T> {
31    type Target = [T];
32    fn deref(&self) -> &Self::Target {
33        &self.0
34    }
35}
36
37#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, Serialize, Deserialize)]
38pub struct FlattenedSubqueryResult<T> {
39    pub key: SubqueryKey<T>,
40    pub value: SubqueryOutput<T>,
41}
42
43impl<T> FlattenedSubqueryResult<T> {
44    pub fn new(key: SubqueryKey<T>, value: SubqueryOutput<T>) -> Self {
45        Self { key, value }
46    }
47}
48
49impl<T: Clone> FlattenedSubqueryResult<T> {
50    pub fn flatten(&self) -> [T; SUBQUERY_RESULT_LEN] {
51        self.to_fixed_array()
52    }
53
54    pub fn to_fixed_array(&self) -> [T; SUBQUERY_RESULT_LEN] {
55        [&self.key.0[..], &self.value.0[..]].concat().try_into().unwrap_or_else(|_| unreachable!())
56    }
57}
58
59/// You should probably use [FlattenedSubqueryResult] instead.
60#[derive(Clone, Copy, Debug)]
61pub struct FieldSubqueryResult<F: Field> {
62    pub subquery: FieldSubquery<F>,
63    pub value: SubqueryOutput<F>,
64}
65
66impl<F: Field> FieldSubqueryResult<F> {
67    pub fn flatten(self) -> FlattenedSubqueryResult<F> {
68        FlattenedSubqueryResult { key: self.subquery.flatten(), value: self.value }
69    }
70    pub fn to_fixed_array(self) -> [F; SUBQUERY_RESULT_LEN] {
71        self.flatten().to_fixed_array()
72    }
73}
74
75impl<F: Field> From<FieldSubqueryResult<F>> for FlattenedSubqueryResult<F> {
76    fn from(value: FieldSubqueryResult<F>) -> Self {
77        value.flatten()
78    }
79}
80
81impl<F: Field> From<FieldSubquery<F>> for SubqueryKey<F> {
82    fn from(subquery: FieldSubquery<F>) -> Self {
83        let mut key = [F::ZERO; 1 + MAX_SUBQUERY_INPUTS];
84        key[0] = F::from(subquery.subquery_type as u64);
85        key[1..].copy_from_slice(&subquery.encoded_subquery_data);
86        Self(key)
87    }
88}
89
90/// Subquery resized to fixed length. For ZK use.
91/// Consider using [SubqueryKey] instead.
92#[derive(Clone, Copy, Debug)]
93pub struct FieldSubquery<T> {
94    pub subquery_type: SubqueryType,
95    pub encoded_subquery_data: [T; MAX_SUBQUERY_INPUTS],
96}
97
98impl<F: Field> FieldSubquery<F> {
99    pub fn flatten(&self) -> SubqueryKey<F> {
100        let mut key = [F::ZERO; SUBQUERY_KEY_LEN];
101        key[0] = F::from(self.subquery_type as u64);
102        key[1..].copy_from_slice(&self.encoded_subquery_data);
103        SubqueryKey(key)
104    }
105}
106
107// unpacked for now
108#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Default)]
109pub struct FieldHeaderSubquery<T> {
110    pub block_number: T,
111    pub field_idx: T,
112}
113
114#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Default)]
115pub struct FieldAccountSubquery<T> {
116    pub block_number: T,
117    pub addr: T, // F::CAPACITY >= 160
118    pub field_idx: T,
119}
120
121#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Default)]
122pub struct FieldStorageSubquery<T> {
123    pub block_number: T,
124    pub addr: T, // F::CAPACITY >= 160
125    pub slot: HiLo<T>,
126}
127
128#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Default)]
129pub struct FieldTxSubquery<T> {
130    pub block_number: T,
131    pub tx_idx: T,
132    pub field_or_calldata_idx: T,
133}
134
135#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Default)]
136pub struct FieldReceiptSubquery<T> {
137    pub block_number: T,
138    pub tx_idx: T,
139    pub field_or_log_idx: T,
140    pub topic_or_data_or_address_idx: T,
141    pub event_schema: HiLo<T>,
142}
143
144#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Default)]
145pub struct FieldSolidityNestedMappingSubquery<T> {
146    pub block_number: T,
147    pub addr: T, // F::CAPACITY >= 160
148    pub mapping_slot: HiLo<T>,
149    pub mapping_depth: T,
150    pub keys: [HiLo<T>; MAX_SOLIDITY_MAPPING_KEYS],
151}
152
153/// A result consists of a pair of the original subquery and the output value.
154/// This type is just a pair, but has nicer JSON serialization.
155#[derive(Clone, Copy, Debug, Hash, Serialize, Deserialize, PartialEq, Eq)]
156pub struct AnySubqueryResult<S, T> {
157    pub subquery: S,
158    pub value: T,
159}
160
161impl<S, T> AnySubqueryResult<S, T> {
162    pub fn new(subquery: S, value: T) -> Self {
163        Self { subquery, value }
164    }
165}
166
167pub type FieldHeaderSubqueryResult<T> = AnySubqueryResult<FieldHeaderSubquery<T>, HiLo<T>>;
168pub type FieldAccountSubqueryResult<T> = AnySubqueryResult<FieldAccountSubquery<T>, HiLo<T>>;
169pub type FieldStorageSubqueryResult<T> = AnySubqueryResult<FieldStorageSubquery<T>, HiLo<T>>;
170pub type FieldTxSubqueryResult<T> = AnySubqueryResult<FieldTxSubquery<T>, HiLo<T>>;
171pub type FieldReceiptSubqueryResult<T> = AnySubqueryResult<FieldReceiptSubquery<T>, HiLo<T>>;
172pub type FieldSolidityNestedMappingSubqueryResult<T> =
173    AnySubqueryResult<FieldSolidityNestedMappingSubquery<T>, HiLo<T>>;