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.to_bech32_string().unwrap_or_default(),
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 #[deprecated(since = "0.56.0", note = "Use `with_storage` instead.")]
66 pub fn with_keys(self, keys: HashMap<String, String>) -> Self {
67 self.with_storage(keys)
68 }
69
70 pub fn add_to_state_file(self, path: &Path) {
71 let mut accounts = if path.exists() {
72 let file = File::open(path)
73 .unwrap_or_else(|_| panic!("Failed to open state file at path {path:#?}"));
74
75 let reader = BufReader::new(file);
76
77 serde_json::from_reader::<_, Vec<SetStateAccount>>(reader).unwrap_or_default()
78 } else {
79 Vec::new()
80 };
81
82 if let Some(existing_account) = accounts
83 .iter_mut()
84 .find(|account| account.address == self.address)
85 {
86 *existing_account = self;
87 } else {
88 accounts.push(self);
89 }
90
91 let file = OpenOptions::new()
92 .write(true)
93 .create(true)
94 .truncate(true)
95 .open(path)
96 .unwrap_or_else(|_| panic!("Failed to open or create state file at path {path:#?}"));
97
98 let writer = BufWriter::new(file);
99 serde_json::to_writer_pretty(writer, &accounts).unwrap_or_else(|_| {
100 panic!("Failed to write updated state accounts to file at path {path:#?}")
101 });
102 }
103}
104
105pub struct ChainSimulatorSetStateRequest {
107 pub accounts: Vec<SetStateAccount>,
108}
109
110impl ChainSimulatorSetStateRequest {
111 pub fn for_accounts(accounts: Vec<SetStateAccount>) -> Self {
112 Self { accounts }
113 }
114}
115
116impl GatewayRequest for ChainSimulatorSetStateRequest {
117 type Payload = Vec<SetStateAccount>;
118 type DecodedJson = SetStateResponse;
119 type Result = String;
120
121 fn get_payload(&self) -> Option<&Self::Payload> {
122 Some(&self.accounts)
123 }
124
125 fn request_type(&self) -> GatewayRequestType {
126 GatewayRequestType::Post
127 }
128
129 fn get_endpoint(&self) -> String {
130 SET_STATE_ENDPOINT.to_owned()
131 }
132
133 fn process_json(&self, decoded: Self::DecodedJson) -> anyhow::Result<Self::Result> {
134 match decoded.code.as_str() {
135 "successful" => Ok(decoded.code),
136 _ => Err(anyhow!("{}", decoded.error)),
137 }
138 }
139}