chia_query/provider_registry/
chia_query_provider.rs1use std::sync::Arc;
17
18use chia_protocol::{Bytes32, CoinSpend};
19use dig_chainsource_interface::{
20 ChainSource, ChainSourceError, ChainSourceProvider, CoinRecord, ProviderInfo, SingletonLineage,
21};
22use tokio::runtime::Handle;
23
24use super::bridge::run_blocking;
25use super::convert::{bytes32_to_hex, coin_record_from_chq, coin_spend_from_chq, map_query_error};
26use super::lineage_walk::{singleton_child_from_spend, walk_singleton_lineage};
27use crate::ChiaQuery;
28
29#[derive(Clone)]
33pub struct ChiaQueryProvider {
34 inner: Arc<ChiaQuery>,
35 handle: Handle,
36 info: ProviderInfo,
37}
38
39impl ChiaQueryProvider {
40 pub fn new(inner: Arc<ChiaQuery>, handle: Handle, info: ProviderInfo) -> Self {
43 Self {
44 inner,
45 handle,
46 info,
47 }
48 }
49}
50
51impl ChainSource for ChiaQueryProvider {
52 type Error = ChainSourceError;
53
54 fn coin_record(&self, coin_id: Bytes32) -> Result<Option<CoinRecord>, Self::Error> {
55 let name = bytes32_to_hex(coin_id);
56 let record = run_blocking(&self.handle, self.inner.get_coin_record_by_name_opt(&name))?
57 .map_err(map_query_error)?;
58 record.as_ref().map(coin_record_from_chq).transpose()
59 }
60
61 fn coin_records_by_puzzle_hash(
62 &self,
63 puzzle_hash: Bytes32,
64 include_spent: bool,
65 ) -> Result<Vec<CoinRecord>, Self::Error> {
66 let hash = bytes32_to_hex(puzzle_hash);
67 let records = run_blocking(
68 &self.handle,
69 self.inner
70 .get_coin_records_by_puzzle_hash(&hash, None, None, include_spent),
71 )?
72 .map_err(map_query_error)?;
73 records.iter().map(coin_record_from_chq).collect()
74 }
75
76 fn coin_records_by_parent(
77 &self,
78 parent_coin_id: Bytes32,
79 ) -> Result<Vec<CoinRecord>, Self::Error> {
80 let parent_ids = [bytes32_to_hex(parent_coin_id)];
82 let records = run_blocking(
83 &self.handle,
84 self.inner
85 .get_coin_records_by_parent_ids(&parent_ids, None, None, true),
86 )?
87 .map_err(map_query_error)?;
88 records.iter().map(coin_record_from_chq).collect()
89 }
90
91 fn coin_spend(&self, coin_id: Bytes32) -> Result<Option<CoinSpend>, Self::Error> {
92 let id = bytes32_to_hex(coin_id);
93 let spend = run_blocking(&self.handle, self.inner.get_coin_spend_opt(&id))?
94 .map_err(map_query_error)?;
95 spend.as_ref().map(coin_spend_from_chq).transpose()
96 }
97
98 fn resolve_singleton_lineage(
99 &self,
100 launcher_id: Bytes32,
101 ) -> Result<Option<SingletonLineage>, Self::Error> {
102 let inner = self.inner.clone();
103 let walk = async move {
104 walk_singleton_lineage(
105 launcher_id,
106 |coin_id| {
107 let inner = inner.clone();
108 async move {
109 let id = bytes32_to_hex(coin_id);
110 match inner.get_coin_spend_opt(&id).await {
111 Ok(Some(spend)) => coin_spend_from_chq(&spend).map(Some),
112 Ok(None) => Ok(None),
113 Err(error) => Err(map_query_error(error)),
114 }
115 }
116 },
117 move |spend| singleton_child_from_spend(spend, launcher_id),
118 )
119 .await
120 };
121 run_blocking(&self.handle, walk)?
122 }
123
124 fn peak_height(&self) -> Result<Option<u32>, Self::Error> {
125 run_blocking(&self.handle, self.inner.peak_height_opt())?.map_err(map_query_error)
126 }
127
128 fn block_timestamp(&self, height: u32) -> Result<Option<u64>, Self::Error> {
129 run_blocking(&self.handle, self.inner.block_timestamp_opt(height))?.map_err(map_query_error)
130 }
131}
132
133impl ChainSourceProvider for ChiaQueryProvider {
134 fn provider_info(&self) -> ProviderInfo {
135 self.info.clone()
136 }
137}