dg_xch_cli_lib/simulator/
mod.rs1pub mod chain_user;
2
3use crate::simulator::chain_user::ChainUser;
4use crate::wallets::memory_wallet::{MemoryWallet, MemoryWalletConfig, MemoryWalletStore};
5use crate::wallets::{Wallet, WalletInfo};
6use bip39::Mnemonic;
7use dg_xch_clients::api::simulator::SimulatorAPI;
8use dg_xch_clients::rpc::simulator::SimulatorClient;
9use dg_xch_core::blockchain::sized_bytes::Bytes32;
10use dg_xch_core::blockchain::wallet_type::WalletType;
11use dg_xch_core::consensus::constants::{ConsensusConstants, SIMULATOR};
12use dg_xch_keys::{decode_puzzle_hash, key_from_mnemonic};
13use lazy_static::lazy_static;
14use std::collections::HashMap;
15use std::io::{Error, ErrorKind};
16use std::sync::atomic::{AtomicBool, Ordering};
17use std::sync::Arc;
18use std::time::Duration;
19use tokio::sync::Mutex;
20use tokio::task::JoinHandle;
21use tokio::time;
22
23lazy_static! {
24 pub static ref UTIL_ADDRESS: Bytes32 =
25 decode_puzzle_hash("xch1ye5dzd44kkatnxx2je4s2agpwtqds5lsm5mlyef7plum5danxalq2dnqap")
26 .unwrap();
27}
28
29pub struct Simulator<'a> {
30 network: ConsensusConstants,
31 client: SimulatorClient,
32 run: Arc<AtomicBool>,
33 background: Mutex<Option<JoinHandle<()>>>,
34 users: Mutex<HashMap<String, Arc<ChainUser<'a>>>>,
35}
36impl<'a> Simulator<'a> {
37 pub fn new(
38 host: &str,
39 port: u16,
40 timeout: u64,
41 additional_headers: &Option<HashMap<String, String>>,
42 network: Option<ConsensusConstants>,
43 ) -> Result<Self, Error> {
44 Ok(Self {
45 network: network.unwrap_or((**SIMULATOR).clone()),
46 client: SimulatorClient::new(host, port, timeout, additional_headers)?,
47 run: Arc::new(AtomicBool::new(false)),
48 background: Mutex::new(None),
49 users: Mutex::new(HashMap::default()),
50 })
51 }
52 pub fn client(&self) -> &SimulatorClient {
53 &self.client
54 }
55 pub fn constants(&self) -> &ConsensusConstants {
56 &self.network
57 }
58 pub async fn get_user(&self, name: &str) -> Option<Arc<ChainUser<'a>>> {
59 self.users.lock().await.get(name).cloned()
60 }
61 pub async fn new_user(
62 &'a self,
63 name: &str,
64 menmonic: Option<String>,
65 ) -> Result<Arc<ChainUser<'a>>, Error> {
66 let mut map_lock = self.users.lock().await;
67 if map_lock.contains_key(name) {
68 return Err(Error::new(ErrorKind::AlreadyExists, "User already exists"));
69 }
70 let mnemonic = match menmonic {
71 Some(s) => Mnemonic::parse(s).map_err(Error::other)?,
72 None => Mnemonic::generate(24).map_err(Error::other)?,
73 };
74 let secret_key = key_from_mnemonic(&mnemonic).map_err(Error::other)?;
75 let chain_user = Arc::new(ChainUser {
76 simulator: self,
77 wallet: Arc::new(MemoryWallet::create_simulator(
78 WalletInfo {
79 id: 0,
80 name: format!("{name}'s Wallet"),
81 wallet_type: WalletType::StandardWallet,
82 constants: Arc::new(self.network.clone()),
83 master_sk: secret_key.clone(),
84 wallet_store: Arc::new(Mutex::new(MemoryWalletStore::new(secret_key, 0))),
85 data: String::new(),
86 },
87 MemoryWalletConfig {
88 fullnode_host: self.client.host.clone(),
89 fullnode_port: self.client.port,
90 fullnode_ssl_path: None,
91 additional_headers: self.client.additional_headers.clone(),
92 },
93 )?),
94 name: name.to_string(),
95 });
96 map_lock.insert(name.to_string(), chain_user.clone());
97 Ok(chain_user)
98 }
99 pub async fn next_blocks(&self, blocks: i64, call_per_block: bool) -> Result<(), Error> {
100 if call_per_block {
101 for _ in 0..blocks {
102 self.client.farm_blocks(*UTIL_ADDRESS, 1, true).await?;
103 }
104 } else {
105 self.client.farm_blocks(*UTIL_ADDRESS, blocks, true).await?;
106 }
107 Ok(())
108 }
109 pub async fn farm_coins(
110 &self,
111 address: Bytes32,
112 blocks: i64,
113 transaction_block: bool,
114 ) -> Result<(), Error> {
115 self.client
116 .farm_blocks(address, blocks, transaction_block)
117 .await
118 .map_err(Into::into)
119 .map(|_| ())
120 }
121 pub async fn is_auto_farming(&self) -> Result<bool, Error> {
122 self.client
123 .get_auto_farming()
124 .await
125 .map_err(Into::into)
126 .map(|r| r.auto_farm_enabled)
127 }
128 pub async fn run(&self, block_interval: Option<Duration>) -> Result<(), Error> {
129 let mut block_interval = time::interval(block_interval.unwrap_or(Duration::from_secs(19)));
130 let run = self.run.clone();
131 if let Some(background) = &mut *self.background.lock().await {
132 if run.load(Ordering::Relaxed) {
133 return Err(Error::new(
134 ErrorKind::AlreadyExists,
135 "Simulator Already Running",
136 ));
137 }
138 run.store(false, Ordering::Relaxed);
139 background.await?;
140 }
141 run.store(true, Ordering::Relaxed);
142 *self.background.lock().await = Some(tokio::spawn(async move {
143 while run.load(Ordering::Relaxed) {
144 block_interval.tick().await;
145 }
146 }));
147 Ok(())
148 }
149 pub async fn stop(&self) -> Result<(), Error> {
150 self.run.store(false, Ordering::Relaxed);
151 if let Some(background) = &mut *self.background.lock().await {
152 background.await?;
153 Ok(())
154 } else {
155 Err(Error::new(
156 ErrorKind::AlreadyExists,
157 "Simulator Not Running",
158 ))
159 }
160 }
161}