1use std::collections::HashMap;
2
3use serde::de::{self, Visitor};
4use serde::{Deserialize, Deserializer, Serialize};
5use serde_json::{json, Value};
6use std::fmt;
7
8use crate::chain::abi::ABI;
9use crate::chain::public_key::PublicKey;
10use crate::chain::signature::Signature;
11use crate::chain::{
12 action::{Action, PermissionLevel},
13 asset::{deserialize_asset, Asset},
14 authority::Authority,
15 block_id::{deserialize_block_id, deserialize_optional_block_id, BlockId},
16 checksum::{deserialize_checksum256, Checksum160, Checksum256},
17 name::{deserialize_name, deserialize_optional_name, deserialize_vec_name, Name},
18 time::{deserialize_optional_timepoint, deserialize_timepoint, TimePoint, TimePointSec},
19 transaction::TransactionHeader,
20 varint::VarUint32,
21};
22
23#[derive(Debug)]
24pub enum ClientError<T> {
25 SIMPLE(SimpleError),
26 SERVER(ServerError<T>),
27 HTTP(HTTPError),
28 ENCODING(EncodingError),
29 NETWORK(String),
30}
31
32impl<T> ClientError<T> {
33 pub fn simple(message: String) -> Self {
34 ClientError::SIMPLE(SimpleError { message })
35 }
36
37 pub fn encoding(message: String) -> Self {
38 ClientError::ENCODING(EncodingError { message })
39 }
40
41 pub fn server(error: T) -> Self {
42 ClientError::SERVER(ServerError { error })
43 }
44}
45
46impl<T> From<EncodingError> for ClientError<T> {
47 fn from(value: EncodingError) -> Self {
48 ClientError::ENCODING(value)
49 }
50}
51
52impl<T> From<String> for ClientError<T> {
53 fn from(value: String) -> Self {
54 ClientError::simple(value)
55 }
56}
57
58#[derive(Debug)]
59pub struct SimpleError {
60 pub message: String,
61}
62
63#[derive(Debug)]
64pub struct ServerError<T> {
65 pub error: T,
66}
67
68#[derive(Debug)]
69pub struct HTTPError {
70 pub code: u16,
71 pub message: String,
72}
73
74#[derive(Debug)]
75pub struct EncodingError {
76 pub message: String,
77}
78
79impl EncodingError {
80 pub fn new(message: String) -> Self {
81 EncodingError { message }
82 }
83}
84
85#[derive(Debug, Serialize, Deserialize)]
100pub struct GetInfoResponse {
101 pub server_version: String,
102 #[serde(deserialize_with = "deserialize_checksum256")]
103 pub chain_id: Checksum256,
104 pub head_block_num: u32,
105 pub last_irreversible_block_num: u32,
106 #[serde(deserialize_with = "deserialize_block_id")]
107 pub last_irreversible_block_id: BlockId,
108 #[serde(deserialize_with = "deserialize_block_id")]
109 pub head_block_id: BlockId,
110 #[serde(deserialize_with = "deserialize_timepoint")]
111 pub head_block_time: TimePoint,
112 #[serde(deserialize_with = "deserialize_name")]
113 pub head_block_producer: Name,
114 pub virtual_block_cpu_limit: u64,
115 pub virtual_block_net_limit: u64,
116 pub block_cpu_limit: u64,
117 pub block_net_limit: u64,
118 pub server_version_string: Option<String>,
119 pub fork_db_head_block_num: Option<u32>,
120 #[serde(deserialize_with = "deserialize_optional_block_id")]
121 pub fork_db_head_block_id: Option<BlockId>,
122 pub server_full_version_string: String,
123 #[serde(deserialize_with = "deserialize_number_or_string")]
124 pub total_cpu_weight: String,
125 #[serde(deserialize_with = "deserialize_number_or_string")]
126 pub total_net_weight: String,
127 pub earliest_available_block_num: u32,
128 pub last_irreversible_block_time: String,
129}
130
131impl GetInfoResponse {
132 pub fn get_transaction_header(&self, seconds_ahead: u32) -> TransactionHeader {
133 let expiration = TimePointSec {
134 seconds: (self.head_block_time.elapsed / 1000 / 1000) as u32 + seconds_ahead,
136 };
137 let id = self.last_irreversible_block_id.bytes.to_vec();
138 let prefix_array = &id[8..12];
139 let prefix = u32::from_ne_bytes(prefix_array.try_into().unwrap());
140 TransactionHeader {
141 max_net_usage_words: VarUint32::default(),
142 max_cpu_usage_ms: 0,
143 delay_sec: VarUint32::default(),
144 expiration,
145 ref_block_num: (self.last_irreversible_block_num & 0xffff) as u16,
146 ref_block_prefix: prefix,
147 }
148 }
149}
150
151#[derive(Debug, Serialize, Deserialize)]
152pub struct ProcessedTransactionReceipt {
153 pub status: String,
154 pub cpu_usage_us: u32,
155 pub net_usage_words: u32,
156}
157
158#[derive(Debug, Serialize, Deserialize)]
159pub struct ProcessedTransaction {
160 pub id: String,
161 pub block_num: u64,
162 pub block_time: String,
163 pub receipt: ProcessedTransactionReceipt,
164 pub elapsed: u64,
165 pub except: Option<SendTransactionResponseError>,
166 pub net_usage: u32,
167 pub scheduled: bool,
168 pub action_traces: Vec<ActionTrace>,
169 pub account_ram_delta: Option<AccountRamDelta>,
170}
171
172#[derive(Debug, Serialize, Deserialize)]
173pub struct SendTransactionResponseExceptionStackContext {
174 pub level: String,
175 pub file: String,
176 pub line: u32,
177 pub method: String,
178 pub hostname: String,
179 pub thread_name: String,
180 pub timestamp: String,
181}
182
183#[derive(Debug, Serialize, Deserialize)]
184pub struct SendTransactionResponseExceptionStack {
185 pub context: SendTransactionResponseExceptionStackContext,
186 pub format: String,
187 pub data: String, }
189
190#[derive(Debug, Serialize, Deserialize)]
191pub struct SendTransactionResponseError {
192 pub code: u32,
193 pub name: String,
194 pub what: String,
195 pub stack: Option<Vec<SendTransactionResponseExceptionStack>>,
196 pub details: Vec<SendTransactionResponseErrorDetails>,
197}
198
199impl SendTransactionResponseError {
200 pub fn print_error(&self) {
201 self.details.iter().for_each(|d| println!("{:?}", d));
202 }
203
204 pub fn get_stack(&self) -> String {
205 self.stack
206 .as_ref()
207 .map(|s| {
208 s.iter()
209 .map(|s| s.format.clone())
210 .collect::<Vec<String>>()
211 .join("\n")
212 })
213 .unwrap_or_default()
214 }
215}
216
217#[derive(Debug, Serialize, Deserialize)]
218pub struct SendTransactionResponseErrorDetails {
219 pub message: String,
220 pub file: String,
221 pub line_number: u32,
222 pub method: String,
223}
224
225#[derive(Debug, Serialize, Deserialize)]
226pub struct ErrorResponse {
227 pub code: u16,
228 pub message: String,
229 pub error: SendTransactionResponseError,
230}
231
232#[derive(Debug, Serialize, Deserialize)]
233pub struct SendTransactionResponse {
234 pub transaction_id: String,
235 pub processed: ProcessedTransaction,
236}
237
238#[derive(Debug, Serialize, Deserialize)]
239pub struct ActionTrace {
240 pub action_ordinal: u32,
241 pub creator_action_ordinal: u32,
242 pub closest_unnotified_ancestor_action_ordinal: u32,
243 pub receipt: ActionReceipt,
244 #[serde(deserialize_with = "deserialize_name")]
245 pub receiver: Name,
246 pub act: Action,
247 pub context_free: bool,
248 pub elapsed: u64,
249 pub console: String,
250 pub trx_id: String,
251 pub block_num: u64,
252 pub block_time: String,
253 pub producer_block_id: Option<String>,
254 pub account_ram_deltas: Vec<AccountRamDelta>,
255 pub except: Option<String>,
256 pub error_code: Option<u32>,
257 pub return_value_hex_data: String,
258}
259
260#[derive(Debug, Serialize, Deserialize)]
261pub struct ActionReceipt {
262 #[serde(deserialize_with = "deserialize_name")]
263 pub receiver: Name,
264 pub act_digest: String,
265 pub global_sequence: u64,
266 pub recv_sequence: u64,
267 pub auth_sequence: Vec<AuthSequence>,
268 pub code_sequence: u64,
269 pub abi_sequence: u64,
270}
271
272#[derive(Debug, Serialize, Deserialize)]
273pub struct AuthSequence {
274 #[serde(deserialize_with = "deserialize_name")]
275 pub account: Name,
276 pub sequence: u64,
277}
278
279#[derive(Debug, Serialize, Deserialize, PartialEq)]
280pub struct AccountRamDelta {
281 #[serde(deserialize_with = "deserialize_name")]
282 pub account: Name,
283 pub delta: i64,
284}
285
286#[derive(Debug, Serialize, Deserialize)]
287pub enum IndexPosition {
288 PRIMARY,
289 SECONDARY,
290 TERTIARY,
291 FOURTH,
292 FIFTH,
293 SIXTH,
294 SEVENTH,
295 EIGHTH,
296 NINTH,
297 TENTH,
298}
299
300#[derive(Debug, Serialize, Deserialize)]
301pub enum TableIndexType {
302 NAME(Name),
303 UINT64(u64),
304 UINT128(u128),
305 FLOAT64(f64),
306 CHECKSUM256(Checksum256),
307 CHECKSUM160(Checksum160),
308}
309
310#[derive(Debug, Serialize, Deserialize)]
311pub struct GetTableRowsParams {
312 #[serde(deserialize_with = "deserialize_name")]
313 pub code: Name,
314 #[serde(deserialize_with = "deserialize_name")]
315 pub table: Name,
316 #[serde(deserialize_with = "deserialize_optional_name")]
317 pub scope: Option<Name>,
318 pub lower_bound: Option<TableIndexType>,
319 pub upper_bound: Option<TableIndexType>,
320 pub limit: Option<u32>,
321 pub reverse: Option<bool>,
322 pub index_position: Option<IndexPosition>,
323 pub show_payer: Option<bool>,
324}
325
326impl GetTableRowsParams {
327 pub fn to_json(&self) -> String {
328 let mut req: HashMap<&str, Value> = HashMap::new();
329 req.insert("json", Value::Bool(false));
330 req.insert("code", Value::String(self.code.to_string()));
331 req.insert("table", Value::String(self.table.to_string()));
332
333 let scope = self.scope.unwrap_or(self.code);
334 req.insert("scope", Value::String(scope.to_string()));
335
336 json!(req).to_string()
337 }
338}
339
340pub struct GetTableRowsResponse<T> {
341 pub rows: Vec<T>,
342 pub more: bool,
343 pub ram_payers: Option<Vec<Name>>,
344 pub next_key: Option<TableIndexType>,
345}
346
347#[derive(Debug, Serialize, Deserialize)]
348pub struct AccountObject {
349 #[serde(deserialize_with = "deserialize_name")]
350 pub account_name: Name,
351 pub head_block_num: u32,
352 #[serde(deserialize_with = "deserialize_timepoint")]
353 pub head_block_time: TimePoint,
354 pub privileged: bool,
355 #[serde(deserialize_with = "deserialize_timepoint")]
356 pub last_code_update: TimePoint,
357 #[serde(deserialize_with = "deserialize_timepoint")]
358 pub created: TimePoint,
359 #[serde(deserialize_with = "deserialize_asset")]
360 pub core_liquid_balance: Asset,
361 pub ram_quota: i64,
362 pub net_weight: i64,
363 pub cpu_weight: i64,
364 pub net_limit: AccountResourceLimit,
365 pub cpu_limit: AccountResourceLimit,
366 pub ram_usage: u64,
367 pub permissions: Vec<AccountPermission>,
368 pub total_resources: Option<AccountTotalResources>,
369 pub self_delegated_bandwidth: Option<SelfDelegatedBandwidth>,
370 pub refund_request: Option<AccountRefundRequest>,
371 pub voter_info: Option<AccountVoterInfo>,
372 pub rex_info: Option<AccountRexInfo>,
373 pub subjective_cpu_bill_limit: Option<AccountResourceLimit>,
374 pub eosio_any_linked_actions: Option<Vec<AccountLinkedAction>>,
375}
376
377#[derive(Debug, Serialize, Deserialize)]
378pub struct AccountRexInfo {
379 version: u32,
380 #[serde(deserialize_with = "deserialize_name")]
381 owner: Name,
382 #[serde(deserialize_with = "deserialize_asset")]
383 vote_stake: Asset,
384 #[serde(deserialize_with = "deserialize_asset")]
385 rex_balance: Asset,
386 #[serde(deserialize_with = "deserialize_i64_from_string_or_i64")]
387 matured_rex: i64,
388 rex_maturities: Vec<AccountRexInfoMaturities>,
389}
390#[derive(Debug, Serialize, Deserialize)]
391pub struct AccountRexInfoMaturities {
392 #[serde(
393 deserialize_with = "deserialize_optional_timepoint",
394 default,
395 skip_serializing_if = "Option::is_none"
396 )]
397 key: Option<TimePoint>,
398 #[serde(
399 deserialize_with = "deserialize_optional_i64_from_string",
400 default,
401 skip_serializing_if = "Option::is_none"
402 )]
403 value: Option<i64>,
404 #[serde(
405 deserialize_with = "deserialize_optional_timepoint",
406 default,
407 skip_serializing_if = "Option::is_none"
408 )]
409 first: Option<TimePoint>,
410 #[serde(
411 deserialize_with = "deserialize_optional_i64_from_string",
412 default,
413 skip_serializing_if = "Option::is_none"
414 )]
415 second: Option<i64>,
416}
417
418#[derive(Debug, Serialize, Deserialize)]
427pub struct AccountResourceLimit {
428 used: i64,
429 available: i64,
430 max: i64,
431 #[serde(
432 deserialize_with = "deserialize_optional_timepoint",
433 default,
434 skip_serializing_if = "Option::is_none"
435 )]
436 last_usage_update_time: Option<TimePoint>,
437 #[serde(
438 deserialize_with = "deserialize_optional_i64_from_string",
439 default,
440 skip_serializing_if = "Option::is_none"
441 )]
442 current_used: Option<i64>,
443}
444
445#[derive(Debug, Serialize, Deserialize)]
446pub struct AccountRefundRequest {
447 #[serde(deserialize_with = "deserialize_name")]
448 owner: Name,
449 #[serde(deserialize_with = "deserialize_timepoint")]
450 request_time: TimePoint,
451 #[serde(deserialize_with = "deserialize_asset")]
452 net_amount: Asset,
453 #[serde(deserialize_with = "deserialize_asset")]
454 cpu_amount: Asset,
455}
456
457#[derive(Debug, Serialize, Deserialize)]
458pub struct ResourceLimit {
459 max: String,
460 available: String,
461 used: String,
462}
463
464#[derive(Debug, Serialize, Deserialize)]
465pub struct AccountTotalResources {
466 #[serde(deserialize_with = "deserialize_name")]
467 owner: Name,
468 #[serde(deserialize_with = "deserialize_asset")]
469 net_weight: Asset,
470 #[serde(deserialize_with = "deserialize_asset")]
471 cpu_weight: Asset,
472 ram_bytes: u64,
473}
474
475#[derive(Debug, Serialize, Deserialize)]
476pub struct SelfDelegatedBandwidth {
477 #[serde(deserialize_with = "deserialize_name")]
478 from: Name,
479 #[serde(deserialize_with = "deserialize_name")]
480 to: Name,
481 #[serde(deserialize_with = "deserialize_asset")]
482 net_weight: Asset,
483 #[serde(deserialize_with = "deserialize_asset")]
484 cpu_weight: Asset,
485}
486
487#[derive(Debug, Serialize, Deserialize)]
497pub struct AccountPermission {
498 #[serde(deserialize_with = "deserialize_name")]
499 parent: Name,
500 #[serde(deserialize_with = "deserialize_name")]
501 perm_name: Name,
502 required_auth: Authority,
503 #[serde(skip_serializing_if = "Option::is_none", default)]
504 pub linked_actions: Option<Vec<AccountLinkedAction>>,
505}
506
507#[derive(Debug, Serialize, Deserialize)]
508pub struct AccountLinkedAction {
509 #[serde(deserialize_with = "deserialize_name")]
510 account: Name,
511 #[serde(deserialize_with = "deserialize_optional_name")]
512 action: Option<Name>,
513}
514
515#[derive(Debug, Serialize, Deserialize)]
516pub struct RequiredAuth {
517 threshold: u32,
518 keys: Vec<Key>,
519 accounts: Vec<Account>,
520 waits: Vec<Wait>,
521}
522
523#[derive(Debug, Serialize, Deserialize)]
524pub struct Wait {
525 wait_sec: u32,
526 weight: u16,
527}
528
529#[derive(Debug, Serialize, Deserialize)]
530pub struct Key {
531 key: String,
532 weight: u16,
533}
534
535#[derive(Debug, Serialize, Deserialize)]
536pub struct Account {
537 weight: u16,
538 permission: PermissionLevel,
539}
540
541#[derive(Debug, Serialize, Deserialize)]
542pub struct AccountVoterInfo {
543 #[serde(deserialize_with = "deserialize_name")]
544 owner: Name,
545 #[serde(deserialize_with = "deserialize_name")]
546 proxy: Name,
547 #[serde(deserialize_with = "deserialize_vec_name")]
548 producers: Vec<Name>,
549 staked: Option<i64>,
550 #[serde(deserialize_with = "deserialize_f64_from_string")]
551 last_vote_weight: f64,
552 #[serde(deserialize_with = "deserialize_f64_from_string")]
553 proxied_vote_weight: f64,
554 #[serde(deserialize_with = "deserialize_bool_from_number")]
555 is_proxy: bool,
556 flags1: Option<u32>,
557 reserved2: u32,
558 reserved3: String,
559}
560
561#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
562pub struct ABIResponse {
563 pub account_name: String,
564 pub abi: ABI,
565}
566
567#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
568pub struct GetBlockResponse {
569 pub time_point: TimePoint,
570 pub producer: Name,
571 pub confirmed: u16,
572 pub pevious: BlockId,
573 pub transaction_mroot: Checksum256,
574 pub action_mroot: Checksum256,
575 pub schedule_version: u32,
576 pub new_producers: Option<NewProducers>,
577 pub header_extensions: Option<HeaderExtension>,
578 pub producer_signature: Signature,
580 pub transactions: Vec<GetBlockResponseTransactionReceipt>,
581 pub block_extensions: Option<Vec<BlockExtension>>,
582 pub id: BlockId,
583 pub block_num: u32,
584 pub ref_block_prefix: u32,
585}
586#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
587pub struct NewProducers {
588 pub version: u32,
589 pub producers: Vec<NewProducersEntry>,
590}
591
592#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
593pub struct NewProducersEntry {
594 pub producer_name: Name,
595 pub block_signing_key: PublicKey,
596}
597
598#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
599pub struct HeaderExtension {
600 pub r#type: u16,
601 pub data: Vec<u8>,
602}
603
604#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
605pub struct GetBlockResponseTransactionReceipt {
606 pub trx: TrxVariant, }
608
609#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
610pub struct TrxVariant {
611 pub id: Checksum256,
612 pub extra: HashMap<String, Value>,
613}
614
615#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
616pub struct BlockExtension {
617 pub r#type: u16,
618 pub data: Vec<u8>,
619}
620
621fn deserialize_number_or_string<'de, D>(deserializer: D) -> Result<String, D::Error>
680where
681 D: Deserializer<'de>,
682{
683 let value = Value::deserialize(deserializer)?;
684 match value {
685 Value::Number(num) => Ok(num.to_string()),
686 Value::String(s) => Ok(s),
687 _ => Err(serde::de::Error::custom("expected a number or a string")),
688 }
689}
690
691fn deserialize_f64_from_string<'de, D>(deserializer: D) -> Result<f64, D::Error>
692where
693 D: Deserializer<'de>,
694{
695 struct StringToF64Visitor;
696
697 impl<'de> Visitor<'de> for StringToF64Visitor {
698 type Value = f64;
699
700 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
701 formatter.write_str("a string that can be parsed into a f64")
702 }
703
704 fn visit_str<E>(self, value: &str) -> Result<f64, E>
705 where
706 E: de::Error,
707 {
708 value.parse::<f64>().map_err(de::Error::custom)
709 }
710 }
711
712 deserializer.deserialize_str(StringToF64Visitor)
713}
714
715fn deserialize_bool_from_number<'de, D>(deserializer: D) -> Result<bool, D::Error>
716where
717 D: Deserializer<'de>,
718{
719 struct NumberToBoolVisitor;
720
721 impl<'de> Visitor<'de> for NumberToBoolVisitor {
722 type Value = bool;
723
724 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
725 formatter.write_str("a number representing a boolean (0 or 1)")
726 }
727
728 fn visit_u64<E>(self, value: u64) -> Result<bool, E>
729 where
730 E: de::Error,
731 {
732 match value {
733 0 => Ok(false),
734 1 => Ok(true),
735 _ => Err(E::custom("expected 0 or 1 for boolean")),
736 }
737 }
738 }
739
740 deserializer.deserialize_any(NumberToBoolVisitor)
741}
742
743fn deserialize_i64_from_string_or_i64<'de, D>(deserializer: D) -> Result<i64, D::Error>
744where
745 D: Deserializer<'de>,
746{
747 struct I64OrStringVisitor;
748
749 impl<'de> serde::de::Visitor<'de> for I64OrStringVisitor {
750 type Value = i64;
751
752 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
753 formatter.write_str("an integer or a string representation of an integer")
754 }
755
756 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
757 where
758 E: serde::de::Error,
759 {
760 value.parse::<i64>().map_err(E::custom)
761 }
762
763 fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
764 where
765 E: serde::de::Error,
766 {
767 Ok(value)
768 }
769
770 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
771 where
772 E: serde::de::Error,
773 {
774 i64::try_from(value).map_err(|_| E::custom("u64 value too large for i64"))
775 }
776 }
777
778 deserializer.deserialize_any(I64OrStringVisitor)
779}
780
781fn deserialize_optional_i64_from_string<'de, D>(deserializer: D) -> Result<Option<i64>, D::Error>
782where
783 D: Deserializer<'de>,
784{
785 struct StringOrI64Visitor;
786
787 impl<'de> Visitor<'de> for StringOrI64Visitor {
788 type Value = Option<i64>;
789
790 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
791 formatter.write_str(
792 "a string representing a 64-bit signed integer, an actual integer, or null",
793 )
794 }
795
796 fn visit_str<E>(self, value: &str) -> Result<Option<i64>, E>
797 where
798 E: de::Error,
799 {
800 value.parse::<i64>().map(Some).map_err(de::Error::custom)
801 }
802
803 fn visit_i64<E>(self, value: i64) -> Result<Option<i64>, E>
804 where
805 E: de::Error,
806 {
807 Ok(Some(value))
808 }
809
810 fn visit_u64<E>(self, value: u64) -> Result<Option<i64>, E>
811 where
812 E: de::Error,
813 {
814 if value <= i64::MAX as u64 {
815 Ok(Some(value as i64))
816 } else {
817 Err(de::Error::custom("u64 value too large for i64"))
818 }
819 }
820
821 fn visit_none<E>(self) -> Result<Option<i64>, E>
822 where
823 E: de::Error,
824 {
825 Ok(None)
826 }
827
828 fn visit_unit<E>(self) -> Result<Option<i64>, E>
829 where
830 E: de::Error,
831 {
832 Ok(None)
833 }
834 }
835
836 deserializer.deserialize_any(StringOrI64Visitor)
837}