snarkvm_ledger_query/
query.rs1use crate::QueryTrait;
17use console::{
18 network::prelude::*,
19 program::{ProgramID, StatePath},
20 types::Field,
21};
22use ledger_store::{BlockStorage, BlockStore};
23use synthesizer_program::Program;
24
25#[derive(Clone)]
26pub enum Query<N: Network, B: BlockStorage<N>> {
27 VM(BlockStore<N, B>),
29 REST(String),
31}
32
33impl<N: Network, B: BlockStorage<N>> From<BlockStore<N, B>> for Query<N, B> {
34 fn from(block_store: BlockStore<N, B>) -> Self {
35 Self::VM(block_store)
36 }
37}
38
39impl<N: Network, B: BlockStorage<N>> From<&BlockStore<N, B>> for Query<N, B> {
40 fn from(block_store: &BlockStore<N, B>) -> Self {
41 Self::VM(block_store.clone())
42 }
43}
44
45impl<N: Network, B: BlockStorage<N>> From<String> for Query<N, B> {
46 fn from(url: String) -> Self {
47 Self::REST(url)
48 }
49}
50
51impl<N: Network, B: BlockStorage<N>> From<&String> for Query<N, B> {
52 fn from(url: &String) -> Self {
53 Self::REST(url.to_string())
54 }
55}
56
57impl<N: Network, B: BlockStorage<N>> From<&str> for Query<N, B> {
58 fn from(url: &str) -> Self {
59 Self::REST(url.to_string())
60 }
61}
62
63#[cfg_attr(feature = "async", async_trait(?Send))]
64impl<N: Network, B: BlockStorage<N>> QueryTrait<N> for Query<N, B> {
65 fn current_state_root(&self) -> Result<N::StateRoot> {
67 match self {
68 Self::VM(block_store) => Ok(block_store.current_state_root()),
69 Self::REST(url) => match N::ID {
70 console::network::MainnetV0::ID => {
71 Ok(Self::get_request(&format!("{url}/mainnet/stateRoot/latest"))?.into_json()?)
72 }
73 console::network::TestnetV0::ID => {
74 Ok(Self::get_request(&format!("{url}/testnet/stateRoot/latest"))?.into_json()?)
75 }
76 console::network::CanaryV0::ID => {
77 Ok(Self::get_request(&format!("{url}/canary/stateRoot/latest"))?.into_json()?)
78 }
79 _ => bail!("Unsupported network ID in inclusion query"),
80 },
81 }
82 }
83
84 #[cfg(feature = "async")]
86 async fn current_state_root_async(&self) -> Result<N::StateRoot> {
87 match self {
88 Self::VM(block_store) => Ok(block_store.current_state_root()),
89 Self::REST(url) => match N::ID {
90 console::network::MainnetV0::ID => {
91 Ok(Self::get_request_async(&format!("{url}/mainnet/stateRoot/latest")).await?.json().await?)
92 }
93 console::network::TestnetV0::ID => {
94 Ok(Self::get_request_async(&format!("{url}/testnet/stateRoot/latest")).await?.json().await?)
95 }
96 console::network::CanaryV0::ID => {
97 Ok(Self::get_request_async(&format!("{url}/canary/stateRoot/latest")).await?.json().await?)
98 }
99 _ => bail!("Unsupported network ID in inclusion query"),
100 },
101 }
102 }
103
104 fn get_state_path_for_commitment(&self, commitment: &Field<N>) -> Result<StatePath<N>> {
106 match self {
107 Self::VM(block_store) => block_store.get_state_path_for_commitment(commitment),
108 Self::REST(url) => match N::ID {
109 console::network::MainnetV0::ID => {
110 Ok(Self::get_request(&format!("{url}/mainnet/statePath/{commitment}"))?.into_json()?)
111 }
112 console::network::TestnetV0::ID => {
113 Ok(Self::get_request(&format!("{url}/testnet/statePath/{commitment}"))?.into_json()?)
114 }
115 console::network::CanaryV0::ID => {
116 Ok(Self::get_request(&format!("{url}/canary/statePath/{commitment}"))?.into_json()?)
117 }
118 _ => bail!("Unsupported network ID in inclusion query"),
119 },
120 }
121 }
122
123 #[cfg(feature = "async")]
125 async fn get_state_path_for_commitment_async(&self, commitment: &Field<N>) -> Result<StatePath<N>> {
126 match self {
127 Self::VM(block_store) => block_store.get_state_path_for_commitment(commitment),
128 Self::REST(url) => match N::ID {
129 console::network::MainnetV0::ID => {
130 Ok(Self::get_request_async(&format!("{url}/mainnet/statePath/{commitment}")).await?.json().await?)
131 }
132 console::network::TestnetV0::ID => {
133 Ok(Self::get_request_async(&format!("{url}/testnet/statePath/{commitment}")).await?.json().await?)
134 }
135 console::network::CanaryV0::ID => {
136 Ok(Self::get_request_async(&format!("{url}/canary/statePath/{commitment}")).await?.json().await?)
137 }
138 _ => bail!("Unsupported network ID in inclusion query"),
139 },
140 }
141 }
142
143 fn current_block_height(&self) -> Result<u32> {
145 match self {
146 Self::VM(block_store) => Ok(block_store.max_height().unwrap_or_default()),
147 Self::REST(url) => match N::ID {
148 console::network::MainnetV0::ID => {
149 Ok(Self::get_request(&format!("{url}/mainnet/block/height/latest"))?.into_json()?)
150 }
151 console::network::TestnetV0::ID => {
152 Ok(Self::get_request(&format!("{url}/testnet/block/height/latest"))?.into_json()?)
153 }
154 console::network::CanaryV0::ID => {
155 Ok(Self::get_request(&format!("{url}/canary/block/height/latest"))?.into_json()?)
156 }
157 _ => bail!("Unsupported network ID in inclusion query"),
158 },
159 }
160 }
161
162 #[cfg(feature = "async")]
164 async fn current_block_height_async(&self) -> Result<u32> {
165 match self {
166 Self::VM(block_store) => Ok(block_store.max_height().unwrap_or_default()),
167 Self::REST(url) => match N::ID {
168 console::network::MainnetV0::ID => {
169 Ok(Self::get_request_async(&format!("{url}/mainnet/block/height/latest")).await?.json().await?)
170 }
171 console::network::TestnetV0::ID => {
172 Ok(Self::get_request_async(&format!("{url}/testnet/block/height/latest")).await?.json().await?)
173 }
174 console::network::CanaryV0::ID => {
175 Ok(Self::get_request_async(&format!("{url}/canary/block/height/latest")).await?.json().await?)
176 }
177 _ => bail!("Unsupported network ID in inclusion query"),
178 },
179 }
180 }
181}
182
183impl<N: Network, B: BlockStorage<N>> Query<N, B> {
184 pub fn get_program(&self, program_id: &ProgramID<N>) -> Result<Program<N>> {
186 match self {
187 Self::VM(block_store) => {
188 block_store.get_program(program_id)?.ok_or_else(|| anyhow!("Program {program_id} not found in storage"))
189 }
190 Self::REST(url) => match N::ID {
191 console::network::MainnetV0::ID => {
192 Ok(Self::get_request(&format!("{url}/mainnet/program/{program_id}"))?.into_json()?)
193 }
194 console::network::TestnetV0::ID => {
195 Ok(Self::get_request(&format!("{url}/testnet/program/{program_id}"))?.into_json()?)
196 }
197 console::network::CanaryV0::ID => {
198 Ok(Self::get_request(&format!("{url}/canary/program/{program_id}"))?.into_json()?)
199 }
200 _ => bail!("Unsupported network ID in inclusion query"),
201 },
202 }
203 }
204
205 #[cfg(feature = "async")]
207 pub async fn get_program_async(&self, program_id: &ProgramID<N>) -> Result<Program<N>> {
208 match self {
209 Self::VM(block_store) => {
210 block_store.get_program(program_id)?.ok_or_else(|| anyhow!("Program {program_id} not found in storage"))
211 }
212 Self::REST(url) => match N::ID {
213 console::network::MainnetV0::ID => {
214 Ok(Self::get_request_async(&format!("{url}/mainnet/program/{program_id}")).await?.json().await?)
215 }
216 console::network::TestnetV0::ID => {
217 Ok(Self::get_request_async(&format!("{url}/testnet/program/{program_id}")).await?.json().await?)
218 }
219 console::network::CanaryV0::ID => {
220 Ok(Self::get_request_async(&format!("{url}/canary/program/{program_id}")).await?.json().await?)
221 }
222 _ => bail!("Unsupported network ID in inclusion query"),
223 },
224 }
225 }
226
227 fn get_request(url: &str) -> Result<ureq::Response> {
229 let response = ureq::get(url).call()?;
230 if response.status() == 200 { Ok(response) } else { bail!("Failed to fetch from {url}") }
231 }
232
233 #[cfg(feature = "async")]
235 async fn get_request_async(url: &str) -> Result<reqwest::Response> {
236 let response = reqwest::get(url).await?;
237 if response.status() == 200 { Ok(response) } else { bail!("Failed to fetch from {url}") }
238 }
239}