static_.rs
1 // Copyright (c) 2025-2026 ACDC Network 2 // This file is part of the alphavm library. 3 // 4 // Alpha Chain | Delta Chain Protocol 5 // International Monetary Graphite. 6 // 7 // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com). 8 // They built world-class ZK infrastructure. We installed the EASY button. 9 // Their cryptography: elegant. Our modifications: bureaucracy-compatible. 10 // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours. 11 // 12 // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0 13 // All modifications and new work: CC0 1.0 Universal Public Domain Dedication. 14 // No rights reserved. No permission required. No warranty. No refunds. 15 // 16 // https://creativecommons.org/publicdomain/zero/1.0/ 17 // SPDX-License-Identifier: CC0-1.0 18 19 use crate::QueryTrait; 20 21 use alphavm_console::{network::prelude::*, program::StatePath, types::Field}; 22 23 use anyhow::{ensure, Context, Result}; 24 use serde::Deserialize; 25 use std::{collections::HashMap, str::FromStr}; 26 27 #[derive(Clone)] 28 pub struct StaticQuery<N: Network> { 29 block_height: u32, 30 state_root: N::StateRoot, 31 state_paths: HashMap<Field<N>, StatePath<N>>, 32 } 33 34 impl<N: Network> StaticQuery<N> { 35 pub fn new(block_height: u32, state_root: N::StateRoot, state_paths: HashMap<Field<N>, StatePath<N>>) -> Self { 36 Self { block_height, state_root, state_paths } 37 } 38 } 39 40 #[derive(Deserialize)] 41 struct StaticQueryInput { 42 state_root: String, 43 height: u32, 44 } 45 46 impl<N: Network> FromStr for StaticQuery<N> { 47 type Err = anyhow::Error; 48 49 fn from_str(s: &str) -> Result<Self> { 50 ensure!(s.trim().starts_with('{'), "Not a static query"); 51 52 let input: StaticQueryInput = serde_json::from_str(s).with_context(|| "Invalid JSON format in static query")?; 53 let state_root = N::StateRoot::from_str(&input.state_root).map_err(|_| anyhow!("Invalid state root format"))?; 54 55 Ok(Self { state_root, block_height: input.height, state_paths: HashMap::new() }) 56 } 57 } 58 59 #[cfg_attr(feature = "async", async_trait::async_trait(?Send))] 60 impl<N: Network> QueryTrait<N> for StaticQuery<N> { 61 /// Returns the current state root. 62 fn current_state_root(&self) -> Result<N::StateRoot> { 63 Ok(self.state_root) 64 } 65 66 /// Returns the current state root (async version). 67 #[cfg(feature = "async")] 68 async fn current_state_root_async(&self) -> Result<N::StateRoot> { 69 // There is no I/O in StaticQuery, so the sync version is identical. 70 self.current_state_root() 71 } 72 73 /// Returns a state path for the given `commitment`. 74 fn get_state_path_for_commitment(&self, commitment: &Field<N>) -> Result<StatePath<N>> { 75 match self.state_paths.get(commitment) { 76 Some(state_path) => Ok(state_path.clone()), 77 None => bail!("Could not find state path for commitment '{commitment}'"), 78 } 79 } 80 81 /// Returns a state path for the given `commitment` (async version). 82 #[cfg(feature = "async")] 83 async fn get_state_path_for_commitment_async(&self, commitment: &Field<N>) -> Result<StatePath<N>> { 84 // There is no I/O in StaticQuery, so the sync version is identical. 85 self.get_state_path_for_commitment(commitment) 86 } 87 88 /// Returns a list of state paths for the given list of `commitment`s. 89 fn get_state_paths_for_commitments(&self, commitments: &[Field<N>]) -> Result<Vec<StatePath<N>>> { 90 commitments 91 .iter() 92 .map(|commitment| self.get_state_path_for_commitment(commitment)) 93 .collect::<Result<Vec<StatePath<N>>>>() 94 } 95 96 /// Returns a list of state paths for the given list of `commitment`s (async version). 97 #[cfg(feature = "async")] 98 async fn get_state_paths_for_commitments_async(&self, commitments: &[Field<N>]) -> Result<Vec<StatePath<N>>> { 99 // There is no I/O in StaticQuery, so the sync version is identical. 100 self.get_state_paths_for_commitments(commitments) 101 } 102 103 /// Returns the current block height. 104 fn current_block_height(&self) -> Result<u32> { 105 Ok(self.block_height) 106 } 107 108 /// Returns the current block height (async version). 109 #[cfg(feature = "async")] 110 async fn current_block_height_async(&self) -> Result<u32> { 111 // There is no I/O in StaticQuery, so the sync version is identical. 112 self.current_block_height() 113 } 114 } 115 116 #[cfg(test)] 117 mod tests { 118 use super::*; 119 use alphavm_console::network::TestnetV0; 120 121 #[test] 122 fn test_static_query_parse() { 123 let json = r#"{"state_root": "sr1dz06ur5spdgzkguh4pr42mvft6u3nwsg5drh9rdja9v8jpcz3czsls9geg", "height": 14}"# 124 .to_string(); 125 let query: Result<StaticQuery<TestnetV0>> = json.parse(); 126 assert!(query.is_ok()); 127 } 128 129 #[test] 130 fn test_static_query_parse_invalid() { 131 let json = r#"{"invalid_key": "sr1dz06ur5spdgzkguh4pr42mvft6u3nwsg5drh9rdja9v8jpcz3czsls9geg", "height": 14}"# 132 .to_string(); 133 let query: Result<StaticQuery<TestnetV0>> = json.parse(); 134 assert!(query.is_err()); 135 } 136 }