Skip to main content

chia_sdk_bindings/
rpc.rs

1use std::sync::Arc;
2
3use bindy::Result;
4use chia_protocol::{Bytes32, SpendBundle};
5use chia_sdk_coinset::{
6    AdditionsAndRemovalsResponse, BlockchainStateResponse, ChiaRpcClient,
7    GetBlockRecordByHeightResponse, GetBlockRecordResponse, GetBlockRecordsResponse,
8    GetBlockResponse, GetBlockSpendsResponse, GetBlocksResponse, GetCoinRecordResponse,
9    GetCoinRecordsResponse, GetMempoolItemResponse, GetMempoolItemsResponse,
10    GetNetworkInfoResponse, GetPuzzleAndSolutionResponse, PushTxResponse,
11};
12use serde::{Serialize, de::DeserializeOwned};
13
14#[cfg(any(feature = "napi", feature = "pyo3"))]
15use chia_protocol::Bytes;
16
17enum RpcClientImpl {
18    Coinset(chia_sdk_coinset::CoinsetClient),
19    #[cfg(any(feature = "napi", feature = "pyo3"))]
20    FullNode(chia_sdk_coinset::FullNodeClient),
21}
22
23impl ChiaRpcClient for RpcClientImpl {
24    type Error = reqwest::Error;
25
26    fn base_url(&self) -> &str {
27        match self {
28            RpcClientImpl::Coinset(client) => client.base_url(),
29            #[cfg(any(feature = "napi", feature = "pyo3"))]
30            RpcClientImpl::FullNode(client) => client.base_url(),
31        }
32    }
33
34    async fn make_post_request<R, B>(
35        &self,
36        endpoint: &str,
37        body: B,
38    ) -> std::result::Result<R, Self::Error>
39    where
40        B: Serialize + Send,
41        R: DeserializeOwned + Send,
42    {
43        match self {
44            RpcClientImpl::Coinset(client) => client.make_post_request(endpoint, body).await,
45            #[cfg(any(feature = "napi", feature = "pyo3"))]
46            RpcClientImpl::FullNode(client) => client.make_post_request(endpoint, body).await,
47        }
48    }
49}
50
51#[derive(Clone)]
52pub struct RpcClient(Arc<RpcClientImpl>);
53
54impl RpcClient {
55    pub fn new(base_url: String) -> Result<Self> {
56        Ok(Self(Arc::new(RpcClientImpl::Coinset(
57            chia_sdk_coinset::CoinsetClient::new(base_url),
58        ))))
59    }
60
61    pub fn testnet11() -> Result<Self> {
62        Ok(Self(Arc::new(RpcClientImpl::Coinset(
63            chia_sdk_coinset::CoinsetClient::testnet11(),
64        ))))
65    }
66
67    pub fn mainnet() -> Result<Self> {
68        Ok(Self(Arc::new(RpcClientImpl::Coinset(
69            chia_sdk_coinset::CoinsetClient::mainnet(),
70        ))))
71    }
72
73    #[cfg(any(feature = "napi", feature = "pyo3"))]
74    pub fn local(cert_bytes: Bytes, key_bytes: Bytes) -> Result<Self> {
75        Ok(Self(Arc::new(RpcClientImpl::FullNode(
76            chia_sdk_coinset::FullNodeClient::new(&cert_bytes, &key_bytes)?,
77        ))))
78    }
79
80    #[cfg(any(feature = "napi", feature = "pyo3"))]
81    pub fn local_with_url(base_url: String, cert_bytes: Bytes, key_bytes: Bytes) -> Result<Self> {
82        Ok(Self(Arc::new(RpcClientImpl::FullNode(
83            chia_sdk_coinset::FullNodeClient::with_base_url(base_url, &cert_bytes, &key_bytes)?,
84        ))))
85    }
86
87    pub async fn get_blockchain_state(&self) -> Result<BlockchainStateResponse> {
88        Ok(self.0.get_blockchain_state().await?)
89    }
90
91    pub async fn get_additions_and_removals(
92        &self,
93        header_hash: Bytes32,
94    ) -> Result<AdditionsAndRemovalsResponse> {
95        Ok(self.0.get_additions_and_removals(header_hash).await?)
96    }
97
98    pub async fn get_block(&self, header_hash: Bytes32) -> Result<GetBlockResponse> {
99        Ok(self.0.get_block(header_hash).await?)
100    }
101
102    pub async fn get_block_record(&self, header_hash: Bytes32) -> Result<GetBlockRecordResponse> {
103        Ok(self.0.get_block_record(header_hash).await?)
104    }
105
106    pub async fn get_block_record_by_height(
107        &self,
108        height: u32,
109    ) -> Result<GetBlockRecordByHeightResponse> {
110        Ok(self.0.get_block_record_by_height(height).await?)
111    }
112
113    pub async fn get_block_records(&self, start: u32, end: u32) -> Result<GetBlockRecordsResponse> {
114        Ok(self.0.get_block_records(start, end).await?)
115    }
116
117    pub async fn get_blocks(
118        &self,
119        start: u32,
120        end: u32,
121        exclude_header_hash: bool,
122        exclude_reorged: bool,
123    ) -> Result<GetBlocksResponse> {
124        Ok(self
125            .0
126            .get_blocks(start, end, exclude_header_hash, exclude_reorged)
127            .await?)
128    }
129
130    pub async fn get_block_spends(&self, header_hash: Bytes32) -> Result<GetBlockSpendsResponse> {
131        Ok(self.0.get_block_spends(header_hash).await?)
132    }
133
134    pub async fn get_coin_record_by_name(&self, name: Bytes32) -> Result<GetCoinRecordResponse> {
135        Ok(self.0.get_coin_record_by_name(name).await?)
136    }
137
138    pub async fn get_coin_records_by_hint(
139        &self,
140        hint: Bytes32,
141        start_height: Option<u32>,
142        end_height: Option<u32>,
143        include_spent_coins: Option<bool>,
144        cursor: Option<String>,
145    ) -> Result<GetCoinRecordsResponse> {
146        Ok(self
147            .0
148            .get_coin_records_by_hint(hint, start_height, end_height, include_spent_coins, cursor)
149            .await?)
150    }
151
152    pub async fn get_coin_records_by_hints(
153        &self,
154        hints: Vec<Bytes32>,
155        start_height: Option<u32>,
156        end_height: Option<u32>,
157        include_spent_coins: Option<bool>,
158        cursor: Option<String>,
159    ) -> Result<GetCoinRecordsResponse> {
160        Ok(self
161            .0
162            .get_coin_records_by_hints(hints, start_height, end_height, include_spent_coins, cursor)
163            .await?)
164    }
165
166    pub async fn get_coin_records_by_names(
167        &self,
168        names: Vec<Bytes32>,
169        start_height: Option<u32>,
170        end_height: Option<u32>,
171        include_spent_coins: Option<bool>,
172        cursor: Option<String>,
173    ) -> Result<GetCoinRecordsResponse> {
174        Ok(self
175            .0
176            .get_coin_records_by_names(names, start_height, end_height, include_spent_coins, cursor)
177            .await?)
178    }
179
180    pub async fn get_coin_records_by_parent_ids(
181        &self,
182        parent_ids: Vec<Bytes32>,
183        start_height: Option<u32>,
184        end_height: Option<u32>,
185        include_spent_coins: Option<bool>,
186        cursor: Option<String>,
187    ) -> Result<GetCoinRecordsResponse> {
188        Ok(self
189            .0
190            .get_coin_records_by_parent_ids(
191                parent_ids,
192                start_height,
193                end_height,
194                include_spent_coins,
195                cursor,
196            )
197            .await?)
198    }
199
200    pub async fn get_coin_records_by_puzzle_hash(
201        &self,
202        puzzle_hash: Bytes32,
203        start_height: Option<u32>,
204        end_height: Option<u32>,
205        include_spent_coins: Option<bool>,
206        cursor: Option<String>,
207    ) -> Result<GetCoinRecordsResponse> {
208        Ok(self
209            .0
210            .get_coin_records_by_puzzle_hash(
211                puzzle_hash,
212                start_height,
213                end_height,
214                include_spent_coins,
215                cursor,
216            )
217            .await?)
218    }
219
220    pub async fn get_coin_records_by_puzzle_hashes(
221        &self,
222        puzzle_hashes: Vec<Bytes32>,
223        start_height: Option<u32>,
224        end_height: Option<u32>,
225        include_spent_coins: Option<bool>,
226        cursor: Option<String>,
227    ) -> Result<GetCoinRecordsResponse> {
228        Ok(self
229            .0
230            .get_coin_records_by_puzzle_hashes(
231                puzzle_hashes,
232                start_height,
233                end_height,
234                include_spent_coins,
235                cursor,
236            )
237            .await?)
238    }
239
240    pub async fn get_puzzle_and_solution(
241        &self,
242        coin_id: Bytes32,
243        height: Option<u32>,
244    ) -> Result<GetPuzzleAndSolutionResponse> {
245        Ok(self.0.get_puzzle_and_solution(coin_id, height).await?)
246    }
247
248    pub async fn push_tx(&self, spend_bundle: SpendBundle) -> Result<PushTxResponse> {
249        Ok(self.0.push_tx(spend_bundle).await?)
250    }
251
252    pub async fn get_network_info(&self) -> Result<GetNetworkInfoResponse> {
253        Ok(self.0.get_network_info().await?)
254    }
255
256    pub async fn get_mempool_item_by_tx_id(
257        &self,
258        tx_id: Bytes32,
259    ) -> Result<GetMempoolItemResponse> {
260        Ok(self.0.get_mempool_item_by_tx_id(tx_id).await?)
261    }
262
263    pub async fn get_mempool_items_by_coin_name(
264        &self,
265        coin_name: Bytes32,
266    ) -> Result<GetMempoolItemsResponse> {
267        Ok(self.0.get_mempool_items_by_coin_name(coin_name).await?)
268    }
269}