1mod encode;
2mod error;
3mod parse;
4
5pub mod debug;
6pub mod util;
7
8use crate::{Account, Block};
9use debug::DebugRpc;
10use json::{Map, Value as JsonValue};
11use serde_json as json;
12use zeroize::{Zeroize, ZeroizeOnDrop};
13
14#[cfg(feature = "serde")]
15use serde::{Deserialize, Serialize};
16
17pub use error::RpcError;
18
19#[cfg(test)]
20#[cfg(feature = "serde")]
21pub(crate) const USIZE_LEN: usize = std::mem::size_of::<usize>();
22
23#[derive(Debug, Clone, Zeroize, ZeroizeOnDrop, PartialEq, Eq)]
25#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
26pub struct BlockInfo {
27 pub height: usize,
29 pub timestamp: u64,
31 pub confirmed: bool,
33 pub block: Block,
35}
36
37#[derive(Debug, Clone, Zeroize, ZeroizeOnDrop, PartialEq, Eq)]
39#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
40pub struct AccountInfo {
41 pub frontier: [u8; 32],
43 pub open_block: [u8; 32],
45 pub balance: u128,
47 #[cfg_attr(feature = "serde", serde(rename = "timestamp"))]
49 pub modified_timestamp: u64,
50 pub block_count: usize,
52 pub version: usize,
54 pub representative: Account,
56 pub weight: u128,
58 pub receivable: usize,
60}
61
62#[derive(Debug, Clone, Zeroize, ZeroizeOnDrop, PartialEq, Eq)]
64#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
65pub struct Receivable {
66 pub recipient: Account,
68 #[cfg_attr(feature = "serde", serde(rename = "hash"))]
70 pub block_hash: [u8; 32],
71 pub amount: u128,
73}
74impl From<(Account, [u8; 32], u128)> for Receivable {
75 fn from(value: (Account, [u8; 32], u128)) -> Self {
76 Receivable {
77 recipient: value.0,
78 block_hash: value.1,
79 amount: value.2,
80 }
81 }
82}
83
84#[derive(Debug, Clone)]
86pub struct Rpc(DebugRpc);
87impl Rpc {
88 pub fn new(url: &str, proxy: impl Into<Option<String>>) -> Result<Rpc, RpcError> {
89 Ok(Rpc(DebugRpc::new(url, proxy)?))
90 }
91
92 pub fn get_url(&self) -> &str {
94 self.0.get_url()
95 }
96
97 pub fn get_proxy(&self) -> Option<&str> {
99 self.0.get_proxy()
100 }
101
102 pub async fn _raw_request(&self, json: JsonValue) -> Result<JsonValue, RpcError> {
104 self.0._raw_request(json).await.result
105 }
106
107 pub async fn command(
109 &self,
110 command: &str,
111 arguments: Map<String, JsonValue>,
112 ) -> Result<JsonValue, RpcError> {
113 self.0.command(command, arguments).await.result
114 }
115
116 pub async fn account_balance(&self, account: &Account) -> Result<u128, RpcError> {
117 self.0.account_balance(account).await.result
118 }
119
120 pub async fn account_history(
123 &self,
124 account: &Account,
125 count: usize,
126 head: Option<[u8; 32]>,
127 offset: Option<usize>,
128 ) -> Result<Vec<Block>, RpcError> {
129 self.0
130 .account_history(account, count, head, offset)
131 .await
132 .result
133 }
134
135 pub async fn account_info(&self, account: &Account) -> Result<Option<AccountInfo>, RpcError> {
138 self.0.account_info(account).await.result
139 }
140
141 pub async fn account_representative(
146 &self,
147 account: &Account,
148 ) -> Result<Option<Account>, RpcError> {
149 self.0.account_representative(account).await.result
150 }
151
152 pub async fn accounts_balances(&self, accounts: &[Account]) -> Result<Vec<u128>, RpcError> {
153 self.0.accounts_balances(accounts).await.result
154 }
155
156 pub async fn accounts_frontiers(
159 &self,
160 accounts: &[Account],
161 ) -> Result<Vec<Option<[u8; 32]>>, RpcError> {
162 self.0.accounts_frontiers(accounts).await.result
163 }
164
165 pub async fn accounts_receivable(
167 &self,
168 accounts: &[Account],
169 count: usize,
170 threshold: u128,
171 ) -> Result<Vec<Vec<Receivable>>, RpcError> {
172 self.0
173 .accounts_receivable(accounts, count, threshold)
174 .await
175 .result
176 }
177
178 pub async fn accounts_representatives(
180 &self,
181 accounts: &[Account],
182 ) -> Result<Vec<Option<Account>>, RpcError> {
183 self.0.accounts_representatives(accounts).await.result
184 }
185
186 pub async fn block_info(&self, hash: [u8; 32]) -> Result<Option<BlockInfo>, RpcError> {
188 self.0.block_info(hash).await.result
189 }
190
191 pub async fn blocks_info(
193 &self,
194 hashes: &[[u8; 32]],
195 ) -> Result<Vec<Option<BlockInfo>>, RpcError> {
196 self.0.blocks_info(hashes).await.result
197 }
198
199 pub async fn process(&self, block: &Block) -> Result<[u8; 32], RpcError> {
201 self.0.process(block).await.result
202 }
203
204 pub async fn work_generate(
206 &self,
207 work_hash: [u8; 32],
208 custom_difficulty: Option<[u8; 8]>,
209 ) -> Result<[u8; 8], RpcError> {
210 self.0
211 .work_generate(work_hash, custom_difficulty)
212 .await
213 .result
214 }
215}
216
217#[cfg(test)]
218#[cfg(feature = "serde")]
219mod serde_tests {
220 use super::*;
221 use crate::{
222 constants::get_genesis_account, constants::ONE_NANO, serde_test, Block, BlockType,
223 Signature,
224 };
225
226 serde_test!(block_info: BlockInfo {
227 height: 939,
228 timestamp: 3902193,
229 confirmed: true,
230 block: Block {
231 block_type: BlockType::Receive,
232 account: get_genesis_account(),
233 previous: [19; 32],
234 representative: get_genesis_account(),
235 balance: ONE_NANO,
236 link: [91; 32],
237 signature: Signature::default(),
238 work: [22; 8]
239 }
240 } => USIZE_LEN + 8 + 1 + 220);
241
242 serde_test!(account_info: AccountInfo {
243 frontier: [92; 32],
244 open_block: [192; 32],
245 balance: 89823892,
246 modified_timestamp: 8932,
247 block_count: 483928329,
248 version: 2,
249 representative: get_genesis_account(),
250 weight: 8439483,
251 receivable: 100
252 } => 32 + 32 + 16 + 8 + USIZE_LEN + USIZE_LEN + 32 + 16 + USIZE_LEN);
253
254 serde_test!(receivable: Receivable {
255 recipient: get_genesis_account(),
256 block_hash: [51; 32],
257 amount: 432894284243
258 } => 32 + 32 + 16);
259}