multiversx_sdk/gateway/
gateway_chain_simulator_set_state.rs1use anyhow::anyhow;
2use serde::{Deserialize, Serialize};
3use std::{
4 collections::HashMap,
5 fs::{File, OpenOptions},
6 io::{BufReader, BufWriter},
7 path::Path,
8};
9
10use crate::data::account::Account;
11
12use super::{GatewayRequest, GatewayRequestType, SET_STATE_ENDPOINT};
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct SetStateResponse {
16 pub data: serde_json::Value,
17 pub error: String,
18 pub code: String,
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize, Default)]
22pub struct SetStateAccount {
23 pub address: String,
24 pub nonce: u64,
25 pub balance: String,
26 pub pairs: HashMap<String, String>,
27 pub code: String,
28 #[serde(default)]
29 pub code_hash: String,
30 #[serde(default)]
31 pub root_hash: String,
32 #[serde(default)]
33 pub code_metadata: String,
34 #[serde(default)]
35 pub owner_address: String,
36 #[serde(default)]
37 pub developer_reward: String,
38}
39
40impl From<Account> for SetStateAccount {
41 fn from(value: Account) -> Self {
42 Self {
43 address: value.address.bech32,
44 nonce: value.nonce,
45 balance: value.balance.to_string(),
46 pairs: HashMap::new(),
47 code: value.code,
48 code_hash: value.code_hash.unwrap_or_default(),
49 root_hash: value.root_hash.unwrap_or_default(),
50 code_metadata: value.code_metadata.unwrap_or_default(),
51 owner_address: value.owner_address.unwrap_or_default(),
52 developer_reward: value.developer_reward.unwrap_or_default(),
53 }
54 }
55}
56
57impl SetStateAccount {
58 pub fn with_storage(mut self, pairs: HashMap<String, String>) -> Self {
60 self.pairs = pairs;
61 self
62 }
63
64 pub fn from_address(address: String) -> Self {
66 Self {
67 address,
68 ..Default::default()
69 }
70 }
71
72 #[deprecated(since = "0.56.0", note = "Use `with_storage` instead.")]
74 pub fn with_keys(self, keys: HashMap<String, String>) -> Self {
75 self.with_storage(keys)
76 }
77
78 pub fn add_to_state_file(self, path: &Path) {
79 let mut accounts = if path.exists() {
80 let file = File::open(path)
81 .unwrap_or_else(|_| panic!("Failed to open state file at path {path:#?}"));
82
83 let reader = BufReader::new(file);
84
85 serde_json::from_reader::<_, Vec<SetStateAccount>>(reader).unwrap_or_default()
86 } else {
87 Vec::new()
88 };
89
90 if let Some(existing_account) = accounts
91 .iter_mut()
92 .find(|account| account.address == self.address)
93 {
94 *existing_account = self;
95 } else {
96 accounts.push(self);
97 }
98
99 let file = OpenOptions::new()
100 .write(true)
101 .create(true)
102 .truncate(true)
103 .open(path)
104 .unwrap_or_else(|_| panic!("Failed to open or create state file at path {path:#?}"));
105
106 let writer = BufWriter::new(file);
107 serde_json::to_writer_pretty(writer, &accounts).unwrap_or_else(|_| {
108 panic!("Failed to write updated state accounts to file at path {path:#?}")
109 });
110 }
111}
112
113pub struct ChainSimulatorSetStateRequest {
115 pub accounts: Vec<SetStateAccount>,
116}
117
118impl ChainSimulatorSetStateRequest {
119 pub fn for_accounts(accounts: Vec<SetStateAccount>) -> Self {
120 Self { accounts }
121 }
122}
123
124impl GatewayRequest for ChainSimulatorSetStateRequest {
125 type Payload = Vec<SetStateAccount>;
126 type DecodedJson = SetStateResponse;
127 type Result = String;
128
129 fn get_payload(&self) -> Option<&Self::Payload> {
130 Some(&self.accounts)
131 }
132
133 fn request_type(&self) -> GatewayRequestType {
134 GatewayRequestType::Post
135 }
136
137 fn get_endpoint(&self) -> String {
138 SET_STATE_ENDPOINT.to_owned()
139 }
140
141 fn process_json(&self, decoded: Self::DecodedJson) -> anyhow::Result<Self::Result> {
142 match decoded.code.as_str() {
143 "successful" => Ok(decoded.code),
144 _ => Err(anyhow!("{}", decoded.error)),
145 }
146 }
147}