1use std::io::{Error, ErrorKind};
2use std::ops::{Deref, DerefMut};
3use std::str::FromStr;
4use std::sync::Arc;
5use std::time::Duration;
6
7use crate::wasm_balance_snapshot::WasmBalanceSnapshot;
8use crate::wasm_block::WasmBlock;
9use crate::wasm_blockchain::WasmBlockchain;
10use crate::wasm_configuration::WasmConfiguration;
11use crate::wasm_io_handler::WasmIoHandler;
12use crate::wasm_nft::WasmNFT;
13use crate::wasm_peer::WasmPeer;
14use crate::wasm_slip::WasmSlip;
15use crate::wasm_time_keeper::WasmTimeKeeper;
16use crate::wasm_transaction::WasmTransaction;
17use crate::wasm_wallet::WasmWallet;
18use js_sys::{Array, BigInt, JsString, Uint8Array};
19use lazy_static::lazy_static;
20use log::{debug, error, info, trace, warn, Level, Log, Metadata, Record};
21use saito_core::core::consensus::blockchain::Blockchain;
22use saito_core::core::consensus::blockchain_sync_state::BlockchainSyncState;
23use saito_core::core::consensus::context::Context;
24use saito_core::core::consensus::mempool::Mempool;
25use saito_core::core::consensus::peers::peer_collection::PeerCollection;
26use saito_core::core::consensus::transaction::{Transaction, TransactionType};
27use saito_core::core::consensus::wallet::{Wallet, NFT};
28use saito_core::core::consensus_thread::{ConsensusEvent, ConsensusStats, ConsensusThread};
29use saito_core::core::defs::{
30 BlockId, Currency, PeerIndex, PrintForLog, SaitoPrivateKey, SaitoPublicKey, StatVariable,
31 Timestamp, CHANNEL_SAFE_BUFFER, STAT_BIN_COUNT,
32};
33use saito_core::core::io::network::{Network, PeerDisconnectType};
34use saito_core::core::io::network_event::NetworkEvent;
35use saito_core::core::io::storage::Storage;
36use saito_core::core::mining_thread::{MiningEvent, MiningThread};
37use saito_core::core::msg::api_message::ApiMessage;
38use saito_core::core::msg::message::Message;
39use saito_core::core::process::keep_time::Timer;
40use saito_core::core::process::process_event::ProcessEvent;
41use saito_core::core::process::version::Version;
42use saito_core::core::routing_thread::{RoutingEvent, RoutingStats, RoutingThread};
43use saito_core::core::stat_thread::StatThread;
44use saito_core::core::util::configuration::Configuration;
45use saito_core::core::util::crypto::{generate_keypair_from_private_key, sign};
46use saito_core::core::verification_thread::{VerificationThread, VerifyRequest};
47use secp256k1::SECP256K1;
48use std::convert::TryInto;
49use tokio::sync::mpsc::Receiver;
50use tokio::sync::{Mutex, RwLock};
51use wasm_bindgen::prelude::*;
52use web_sys::console;
53
54#[wasm_bindgen]
55pub struct SaitoWasm {
56 pub(crate) routing_thread: RoutingThread,
57 consensus_thread: ConsensusThread,
58 mining_thread: MiningThread,
59 verification_thread: VerificationThread,
60 stat_thread: StatThread,
61 receiver_for_router: Receiver<RoutingEvent>,
62 receiver_for_consensus: Receiver<ConsensusEvent>,
63 receiver_for_miner: Receiver<MiningEvent>,
64 receiver_for_verification: Receiver<VerifyRequest>,
65 receiver_for_stats: Receiver<String>,
66 pub(crate) context: Context,
67 wallet: WasmWallet,
68 blockchain: WasmBlockchain,
69}
70
71lazy_static! {
72 pub static ref SAITO: Mutex<Option<SaitoWasm>> =
73 Mutex::new(Some(new(1, true, 100_000, 0, 60, false)));
74 static ref CONFIGS: Arc<RwLock<dyn Configuration + Send + Sync>> =
75 Arc::new(RwLock::new(WasmConfiguration::new()));
76 static ref PRIVATE_KEY: Mutex<String> = Mutex::new("".to_string());
77}
78
79pub fn new(
80 haste_multiplier: u64,
81 enable_stats: bool,
82 genesis_period: BlockId,
83 social_stake: Currency,
84 social_stake_period: BlockId,
85 delete_old_blocks: bool,
86) -> SaitoWasm {
87 info!("creating new saito wasm instance");
88 console_error_panic_hook::set_once();
89
90 let wallet = Arc::new(RwLock::new(Wallet::new([0; 32], [0; 33])));
91
92 let configuration: Arc<RwLock<dyn Configuration + Send + Sync>> = CONFIGS.clone();
93
94 let channel_size = 1_000_000;
95
96 if channel_size < CHANNEL_SAFE_BUFFER * 2 {
97 error!(
98 "channel_size < CHANNEL_SAFE_BUFFER x 2 : {:?}",
99 CHANNEL_SAFE_BUFFER * 2
100 );
101 panic!("cannot continue");
102 }
103
104 let peers = Arc::new(RwLock::new(PeerCollection::default()));
105 let context = Context {
106 blockchain_lock: Arc::new(RwLock::new(Blockchain::new(
107 wallet.clone(),
108 genesis_period,
109 social_stake,
110 social_stake_period,
111 ))),
112 mempool_lock: Arc::new(RwLock::new(Mempool::new(wallet.clone()))),
113 wallet_lock: wallet.clone(),
114 config_lock: configuration.clone(),
115 };
116
117 let (sender_to_consensus, receiver_in_mempool) = tokio::sync::mpsc::channel(channel_size);
118 let (sender_to_blockchain, receiver_in_blockchain) = tokio::sync::mpsc::channel(channel_size);
119 let (sender_to_miner, receiver_in_miner) = tokio::sync::mpsc::channel(channel_size);
120 let (sender_to_stat, receiver_in_stats) = tokio::sync::mpsc::channel(channel_size);
121 let (sender_to_verification, receiver_in_verification) =
122 tokio::sync::mpsc::channel(channel_size);
123
124 let timer = Timer {
125 time_reader: Arc::new(WasmTimeKeeper {}),
126 hasten_multiplier: haste_multiplier,
127 start_time: js_sys::Date::now() as Timestamp,
128 };
129
130 SaitoWasm {
131 routing_thread: RoutingThread {
132 blockchain_lock: context.blockchain_lock.clone(),
133 mempool_lock: context.mempool_lock.clone(),
134 sender_to_consensus: sender_to_consensus.clone(),
135 sender_to_miner: sender_to_miner.clone(),
136 config_lock: context.config_lock.clone(),
137 timer: timer.clone(),
138 wallet_lock: wallet.clone(),
139 network: Network::new(
140 Box::new(WasmIoHandler {}),
141 peers.clone(),
142 context.wallet_lock.clone(),
143 context.config_lock.clone(),
144 timer.clone(),
145 ),
146 storage: Storage::new(Box::new(WasmIoHandler {})),
147 reconnection_timer: 0,
148 peer_removal_timer: 0,
149 peer_file_write_timer: 0,
150 last_emitted_block_fetch_count: 0,
151 stats: RoutingStats::new(sender_to_stat.clone()),
152 senders_to_verification: vec![sender_to_verification.clone()],
153 last_verification_thread_index: 0,
154 stat_sender: sender_to_stat.clone(),
155 blockchain_sync_state: BlockchainSyncState::new(10),
156 },
157 consensus_thread: ConsensusThread {
158 mempool_lock: context.mempool_lock.clone(),
159 blockchain_lock: context.blockchain_lock.clone(),
160 wallet_lock: context.wallet_lock.clone(),
161 generate_genesis_block: false,
162 sender_to_router: sender_to_blockchain.clone(),
163 sender_to_miner: sender_to_miner.clone(),
164 block_producing_timer: 0,
165 timer: timer.clone(),
166 network: Network::new(
167 Box::new(WasmIoHandler {}),
168 peers.clone(),
169 context.wallet_lock.clone(),
170 configuration.clone(),
171 timer.clone(),
172 ),
173 storage: Storage::new(Box::new(WasmIoHandler {})),
174 stats: ConsensusStats::new(sender_to_stat.clone()),
175 txs_for_mempool: vec![],
176 stat_sender: sender_to_stat.clone(),
177 config_lock: configuration.clone(),
178 produce_blocks_by_timer: true,
179 delete_old_blocks,
180 },
181 mining_thread: MiningThread {
182 wallet_lock: context.wallet_lock.clone(),
183 sender_to_mempool: sender_to_consensus.clone(),
184 timer: timer.clone(),
185 miner_active: false,
186 target: [0; 32],
187 target_id: 0,
188 difficulty: 0,
189 public_key: [0; 33],
190 mined_golden_tickets: 0,
191 stat_sender: sender_to_stat.clone(),
192 config_lock: configuration.clone(),
193 enabled: true,
194 mining_iterations: 1_000,
195 mining_start: 0,
196 },
197 verification_thread: VerificationThread {
198 sender_to_consensus: sender_to_consensus.clone(),
199 blockchain_lock: context.blockchain_lock.clone(),
200 peer_lock: peers.clone(),
201 wallet_lock: wallet.clone(),
202 processed_txs: StatVariable::new(
203 "verification::processed_txs".to_string(),
204 STAT_BIN_COUNT,
205 sender_to_stat.clone(),
206 ),
207 processed_blocks: StatVariable::new(
208 "verification::processed_blocks".to_string(),
209 STAT_BIN_COUNT,
210 sender_to_stat.clone(),
211 ),
212 processed_msgs: StatVariable::new(
213 "verification::processed_msgs".to_string(),
214 STAT_BIN_COUNT,
215 sender_to_stat.clone(),
216 ),
217 invalid_txs: StatVariable::new(
218 "verification::invalid_txs".to_string(),
219 STAT_BIN_COUNT,
220 sender_to_stat.clone(),
221 ),
222 stat_sender: sender_to_stat.clone(),
223 },
224 stat_thread: StatThread {
225 stat_queue: Default::default(),
226 io_interface: Box::new(WasmIoHandler {}),
227 enabled: enable_stats,
228 },
229 receiver_for_router: receiver_in_blockchain,
230 receiver_for_consensus: receiver_in_mempool,
231 receiver_for_miner: receiver_in_miner,
232 receiver_for_verification: receiver_in_verification,
233 wallet: WasmWallet::new_from(
234 context.wallet_lock.clone(),
235 Network::new(
236 Box::new(WasmIoHandler {}),
237 peers.clone(),
238 context.wallet_lock.clone(),
239 configuration.clone(),
240 timer.clone(),
241 ),
242 ),
243 blockchain: WasmBlockchain {
244 blockchain_lock: context.blockchain_lock.clone(),
245 },
246 context,
247 receiver_for_stats: receiver_in_stats,
248 }
249}
250
251struct WasmLogger {}
252
253impl Log for WasmLogger {
254 fn enabled(&self, metadata: &Metadata) -> bool {
255 metadata.level() <= log::max_level()
256 }
257
258 fn log(&self, record: &Record) {
259 if !self.enabled(record.metadata()) {
260 return;
261 }
262 log(record)
263 }
264
265 fn flush(&self) {}
266}
267pub(crate) struct Style<'s> {
268 pub trace: &'s str,
269 pub debug: &'s str,
270 pub info: &'s str,
271 pub warn: &'s str,
272 pub error: &'s str,
273 pub file_line: &'s str,
274 pub text: &'s str,
275}
276
277impl Style<'static> {
278 pub const fn default() -> Self {
280 macro_rules! bg_color {
281 ($color:expr) => {
282 concat!("color: white; padding: 0 3px; background: ", $color, ";")
283 };
284 }
285
286 Style {
287 trace: bg_color!("gray"),
288 debug: bg_color!("blue"),
289 info: bg_color!("green"),
290 warn: bg_color!("orange"),
291 error: bg_color!("darkred"),
292 file_line: "font-weight: bold; color: inherit",
293 text: "background: inherit; color: inherit",
294 }
295 }
296}
297const STYLE: Style<'static> = Style::default();
298
299pub fn log(record: &Record) {
300 let console_log = match record.level() {
301 Level::Error => console::error_4,
302 Level::Warn => console::warn_4,
303 Level::Info => console::info_4,
304 Level::Debug => console::log_4,
305 Level::Trace => console::debug_4,
306 };
307
308 let message = {
309 let message = format!(
310 "%c%c%c{text}",
311 text = record.args(),
317 );
318 JsValue::from(&message)
319 };
320
321 let level_style = {
322 let style_str = match record.level() {
323 Level::Trace => STYLE.trace,
324 Level::Debug => STYLE.debug,
325 Level::Info => STYLE.info,
326 Level::Warn => STYLE.warn,
327 Level::Error => STYLE.error,
328 };
329
330 JsValue::from(style_str)
331 };
332
333 let file_line_style = JsValue::from_str(STYLE.file_line);
334 let text_style = JsValue::from_str(STYLE.text);
335 console_log(&message, &level_style, &file_line_style, &text_style);
336}
337
338#[wasm_bindgen]
339pub async fn initialize(
340 json: JsString,
341 private_key: JsString,
342 log_level_num: u8,
343 hasten_multiplier: u64,
344 delete_old_blocks: bool,
345) -> Result<JsValue, JsValue> {
346 let log_level = match log_level_num {
349 0 => log::Level::Error,
350 1 => log::Level::Warn,
351 2 => log::Level::Info,
352 3 => log::Level::Debug,
353 4 => log::Level::Trace,
354 _ => log::Level::Info,
355 };
356
357 log::set_logger(&WasmLogger {}).unwrap();
358 log::set_max_level(log_level.to_level_filter());
359
360 trace!("trace test");
363 debug!("debug test");
364 info!("initializing saito-wasm");
365
366 let mut enable_stats = true;
367 let mut genesis_period = 100_000;
368 let mut social_stake = 0;
369 let mut social_stake_period = 60;
370 {
371 info!("setting configs...");
372 let mut configs = CONFIGS.write().await;
373 info!("config lock acquired");
374
375 let str: String = json.into();
376 let config = WasmConfiguration::new_from_json(str.as_str());
377
378 if config.is_err() {
379 error!("failed parsing configs. {:?}", config.err().unwrap());
380 } else {
381 let config = config.unwrap();
382 if config.is_browser() {
383 enable_stats = false;
384 }
385 info!("config : {:?}", config);
386 configs.replace(&config);
387 genesis_period = configs.get_consensus_config().unwrap().genesis_period;
388 social_stake = configs.get_consensus_config().unwrap().default_social_stake;
389 social_stake_period = configs
390 .get_consensus_config()
391 .unwrap()
392 .default_social_stake_period;
393 }
394 }
395
396 let mut saito = SAITO.lock().await;
397
398 info!("genesis_period = {:?}", genesis_period);
399 info!("social_stake = {:?}", social_stake);
400 saito.replace(new(
401 hasten_multiplier,
402 enable_stats,
403 genesis_period,
404 social_stake,
405 social_stake_period,
406 delete_old_blocks,
407 ));
408
409 let private_key: SaitoPrivateKey = string_to_hex(private_key).or(Err(JsValue::from(
410 "Failed parsing private key string to key",
411 )))?;
412 {
413 let mut wallet = saito.as_ref().unwrap().context.wallet_lock.write().await;
414 if private_key != [0; 32] {
415 let keys = generate_keypair_from_private_key(private_key.as_slice());
416 wallet.private_key = keys.1;
417 wallet.public_key = keys.0;
418 }
419 info!("current core version : {:?}", wallet.core_version);
420 }
421
422 saito.as_mut().unwrap().stat_thread.on_init().await;
423 saito.as_mut().unwrap().mining_thread.on_init().await;
424 saito.as_mut().unwrap().verification_thread.on_init().await;
425 saito.as_mut().unwrap().routing_thread.on_init().await;
426 saito.as_mut().unwrap().consensus_thread.on_init().await;
427
428 Ok(JsValue::from("initialized"))
429}
430
431#[wasm_bindgen]
432pub async fn create_transaction(
433 public_key: JsString,
434 amount: u64,
435 fee: u64,
436 force_merge: bool,
437) -> Result<WasmTransaction, JsValue> {
438 trace!("create_transaction : {:?}", public_key.to_string());
439 let saito = SAITO.lock().await;
440 let mut wallet = saito.as_ref().unwrap().context.wallet_lock.write().await;
441 let key = string_to_key(public_key).or(Err(JsValue::from(
442 "Failed parsing public key string to key",
443 )))?;
444
445 let config_lock = saito.as_ref().unwrap().routing_thread.config_lock.clone();
446 let configs = config_lock.read().await;
447 let genesis_period = configs.get_consensus_config().unwrap().genesis_period;
448 let blockchain = saito.as_ref().unwrap().context.blockchain_lock.read().await;
449 let latest_block_id = blockchain.get_latest_block_id();
450
451 let transaction = Transaction::create(
452 &mut wallet,
453 key,
454 amount,
455 fee,
456 force_merge,
457 Some(&saito.as_ref().unwrap().consensus_thread.network),
458 latest_block_id,
459 genesis_period,
460 );
461 if transaction.is_err() {
462 error!(
463 "failed creating transaction. {:?}",
464 transaction.err().unwrap()
465 );
466 return Err(JsValue::from("Failed creating transaction"));
467 }
468 let transaction = transaction.unwrap();
469 let wasm_transaction = WasmTransaction::from_transaction(transaction);
470 Ok(wasm_transaction)
471}
472
473#[wasm_bindgen]
474pub async fn create_transaction_with_multiple_payments(
475 public_keys: js_sys::Array,
476 amounts: js_sys::BigUint64Array,
477 fee: u64,
478 _force_merge: bool,
479) -> Result<WasmTransaction, JsValue> {
480 let saito = SAITO.lock().await;
481 let mut wallet = saito.as_ref().unwrap().context.wallet_lock.write().await;
482
483 let config_lock = saito.as_ref().unwrap().routing_thread.config_lock.clone();
484 let configs = config_lock.read().await;
485 let genesis_period = configs.get_consensus_config().unwrap().genesis_period;
486 let blockchain = saito.as_ref().unwrap().context.blockchain_lock.read().await;
487 let latest_block_id = blockchain.get_latest_block_id();
488
489 let keys: Vec<SaitoPublicKey> = string_array_to_base58_keys(public_keys);
490 let amounts: Vec<Currency> = amounts.to_vec();
491
492 if keys.len() != amounts.len() {
493 return Err(JsValue::from("keys and payments have different counts"));
494 }
495
496 let transaction = Transaction::create_with_multiple_payments(
497 &mut wallet,
498 keys,
499 amounts,
500 fee,
501 Some(&saito.as_ref().unwrap().consensus_thread.network),
502 latest_block_id,
503 genesis_period,
504 );
505 if transaction.is_err() {
506 error!(
507 "failed creating transaction. {:?}",
508 transaction.err().unwrap()
509 );
510 return Err(JsValue::from("Failed creating transaction"));
511 }
512 let transaction = transaction.unwrap();
513 let wasm_transaction = WasmTransaction::from_transaction(transaction);
514 Ok(wasm_transaction)
515}
516
517#[wasm_bindgen]
518pub async fn create_bound_transaction(
519 amt: u64,
520 bid: u64,
521 tid: u64,
522 sid: u64,
523 num: u32,
524 deposit: u64,
525 change: u64,
526 data: String,
527 fee: u64,
528 recipient_public_key: JsString,
529 nft_type: JsString,
530) -> Result<WasmTransaction, JsValue> {
531 let saito = SAITO.lock().await;
532 let config_lock = saito.as_ref().unwrap().routing_thread.config_lock.clone();
533 let configs = config_lock.read().await;
534 let genesis_period = configs.get_consensus_config().unwrap().genesis_period;
535 let blockchain = saito.as_ref().unwrap().context.blockchain_lock.read().await;
536 let latest_block_id = blockchain.get_latest_block_id();
537 let mut wallet = saito.as_ref().unwrap().context.wallet_lock.write().await;
538
539 info!("Received in saitowasm.rs:");
540 info!("Amount: {}", amt);
541 info!("Bid: {}", bid);
542 info!("Tid: {}", tid);
543 info!("Sid: {}", sid);
544 info!("Num: {}", num);
545 info!("Deposit: {}", deposit);
546 info!("Change: {}", change);
547 info!("Image data JSON: {}", data);
548 info!("fee: {}", fee);
549 info!("recipient_public_key: {}", recipient_public_key);
550
551 let serialized_data = match serde_json::to_vec(&data) {
553 Ok(vec) => vec,
554 Err(e) => {
555 error!("Failed to serialize data: {}", e);
556 return Err(JsValue::from_str("Failed to serialize data"));
557 }
558 };
559
560 let serialized_data_u32: Vec<u32> = serialized_data
562 .chunks(4)
563 .map(|chunk| {
564 let mut bytes = [0u8; 4];
565 for (i, &byte) in chunk.iter().enumerate() {
566 bytes[i] = byte;
567 }
568 u32::from_le_bytes(bytes)
569 })
570 .collect();
571
572 let key = string_to_key(recipient_public_key).or(Err(JsValue::from(
573 "Failed parsing public key string to key",
574 )))?;
575
576 let transaction = wallet
577 .create_bound_transaction(
578 amt,
579 bid,
580 tid,
581 sid,
582 deposit,
583 serialized_data_u32,
584 &key,
585 Some(&saito.as_ref().unwrap().consensus_thread.network),
586 latest_block_id,
587 genesis_period,
588 nft_type.as_string().unwrap(),
589 )
590 .await;
591
592 if transaction.is_err() {
593 error!(
594 "failed creating transaction. {:?}",
595 transaction.err().unwrap()
596 );
597 return Err(JsValue::from("Failed creating transaction"));
598 }
599
600 let transaction = transaction.unwrap();
601
602 info!("wasm transaction: {:}", transaction);
603 let wasm_transaction = WasmTransaction::from_transaction(transaction);
604
605 Ok(wasm_transaction)
606}
607
608#[wasm_bindgen]
609pub async fn create_send_bound_transaction(
610 amt: u64,
611 nft_id: String,
612 data: String,
613 recipient_public_key: JsString,
614) -> Result<WasmTransaction, JsValue> {
615 let saito = SAITO.lock().await;
616 let mut wallet = saito.as_ref().unwrap().context.wallet_lock.write().await;
617
618 let nft_id_vec = hex::decode(&nft_id)
620 .map_err(|_| JsValue::from_str("Failed to decode nft_id hex string"))?;
621
622 let serialized_data =
623 serde_json::to_vec(&data).map_err(|_| JsValue::from_str("Failed to serialize data"))?;
624 let serialized_data_u32: Vec<u32> = serialized_data
625 .chunks(4)
626 .map(|chunk| {
627 let mut bytes = [0u8; 4];
628 for (i, &b) in chunk.iter().enumerate() {
629 bytes[i] = b;
630 }
631 u32::from_le_bytes(bytes)
632 })
633 .collect();
634
635 let key = string_to_key(recipient_public_key).or(Err(JsValue::from_str(
636 "Failed parsing public key string to key",
637 )))?;
638
639 let tx = wallet
640 .create_send_bound_transaction(amt, nft_id_vec, serialized_data_u32, &key)
641 .await
642 .map_err(|_| JsValue::from_str("Failed to transfer NFT transaction"))?;
643
644 let wasm_transaction = WasmTransaction::from_transaction(tx);
645 Ok(wasm_transaction)
646}
647
648#[wasm_bindgen]
649pub async fn get_nft_list() -> Result<Array, JsValue> {
650 let saito = SAITO.lock().await;
651 let wallet = saito.as_ref().unwrap().context.wallet_lock.read().await;
652
653 let nft_array = Array::new();
654 for nft in wallet.get_nft_list().iter() {
655 nft_array.push(&WasmNFT::from_nft(nft.clone()).into());
656 }
657
658 Ok(nft_array)
659}
660
661#[wasm_bindgen]
662pub async fn get_latest_block_hash() -> JsString {
663 debug!("get_latest_block_hash");
664 let saito = SAITO.lock().await;
665 let blockchain = saito.as_ref().unwrap().context.blockchain_lock.read().await;
666 let hash = blockchain.get_latest_block_hash();
667
668 hash.to_hex().into()
669}
670
671#[wasm_bindgen]
672pub async fn get_block(block_hash: JsString) -> Result<WasmBlock, JsValue> {
673 let block_hash = string_to_hex(block_hash).or(Err(JsValue::from(
674 "Failed parsing block hash string to key",
675 )))?;
676
677 let saito = SAITO.lock().await;
678 let blockchain = saito
679 .as_ref()
680 .unwrap()
681 .routing_thread
682 .blockchain_lock
683 .read()
684 .await;
685
686 let result = blockchain.get_block(&block_hash);
687
688 if result.is_none() {
689 warn!("block {:?} not found", block_hash.to_hex());
690 return Err(JsValue::from("block not found"));
691 }
692 let block = result.cloned().unwrap();
693
694 Ok(WasmBlock::from_block(block))
695}
696
697#[wasm_bindgen]
698pub async fn process_new_peer(peer_index: PeerIndex, ip: JsString) {
699 debug!("process_new_peer : {:?} - {:?}", peer_index, ip);
700 let mut saito = SAITO.lock().await;
701 let s = ip.as_string();
702 if s.is_none() {
703 debug!("cannot parse ip string : {:?}", ip);
704 return;
705 }
706 let ip = s;
707
708 saito
709 .as_mut()
710 .unwrap()
711 .routing_thread
712 .process_network_event(NetworkEvent::PeerConnectionResult {
713 result: Ok((peer_index, ip)),
714 })
715 .await;
716}
717
718#[wasm_bindgen]
719pub async fn process_stun_peer(peer_index: PeerIndex, public_key: JsString) -> Result<(), JsValue> {
720 debug!(
721 "processing stun peer with index: {:?} and public key: {:?} ",
722 peer_index, public_key
723 );
724 let mut saito = SAITO.lock().await;
725 let key: SaitoPublicKey = string_to_key(public_key.into())
726 .map_err(|e| JsValue::from_str(&format!("Failed to parse public key: {}", e)))?;
727
728 saito
729 .as_mut()
730 .unwrap()
731 .routing_thread
732 .process_network_event(NetworkEvent::AddStunPeer {
733 peer_index,
734 public_key: key,
735 })
736 .await;
737 Ok(())
738}
739
740#[wasm_bindgen]
741pub async fn remove_stun_peer(peer_index: PeerIndex) {
742 debug!(
743 "removing stun peer with index: {:?} from netowrk ",
744 peer_index
745 );
746 let mut saito = SAITO.lock().await;
747 saito
748 .as_mut()
749 .unwrap()
750 .routing_thread
751 .process_network_event(NetworkEvent::RemoveStunPeer { peer_index })
752 .await;
753}
754
755#[wasm_bindgen]
756pub async fn get_next_peer_index() -> BigInt {
757 let mut saito = SAITO.lock().await;
758 let mut peers = saito
759 .as_mut()
760 .unwrap()
761 .routing_thread
762 .network
763 .peer_lock
764 .write()
765 .await;
766
767 BigInt::from(peers.peer_counter.get_next_index())
768}
769
770#[wasm_bindgen]
771pub async fn process_peer_disconnection(peer_index: u64) {
772 debug!("process_peer_disconnection : {:?}", peer_index);
773 let mut saito = SAITO.lock().await;
774 saito
775 .as_mut()
776 .unwrap()
777 .routing_thread
778 .process_network_event(NetworkEvent::PeerDisconnected {
779 peer_index,
780 disconnect_type: PeerDisconnectType::ExternalDisconnect,
781 })
782 .await;
783}
784
785#[wasm_bindgen]
786pub async fn process_msg_buffer_from_peer(buffer: js_sys::Uint8Array, peer_index: u64) {
787 let mut saito = SAITO.lock().await;
788 let buffer = buffer.to_vec();
789
790 saito
791 .as_mut()
792 .unwrap()
793 .routing_thread
794 .process_network_event(NetworkEvent::IncomingNetworkMessage { peer_index, buffer })
795 .await;
796}
797
798#[wasm_bindgen]
799pub async fn process_fetched_block(
800 buffer: js_sys::Uint8Array,
801 hash: js_sys::Uint8Array,
802 block_id: BlockId,
803 peer_index: PeerIndex,
804) {
805 let mut saito = SAITO.lock().await;
806 saito
807 .as_mut()
808 .unwrap()
809 .routing_thread
810 .process_network_event(NetworkEvent::BlockFetched {
811 block_hash: hash.to_vec().try_into().unwrap(),
812 block_id,
813 peer_index,
814 buffer: buffer.to_vec(),
815 })
816 .await;
817}
818
819#[wasm_bindgen]
820pub async fn process_failed_block_fetch(hash: js_sys::Uint8Array, block_id: u64, peer_index: u64) {
821 let mut saito = SAITO.lock().await;
822 saito
823 .as_mut()
824 .unwrap()
825 .routing_thread
826 .process_network_event(NetworkEvent::BlockFetchFailed {
827 block_hash: hash.to_vec().try_into().unwrap(),
828 peer_index,
829 block_id,
830 })
831 .await;
832}
833
834#[wasm_bindgen]
835pub async fn process_timer_event(duration_in_ms: u64) {
836 let mut saito = SAITO.lock().await;
837 let saito = saito.as_mut().unwrap();
838
839 let duration = Duration::from_millis(duration_in_ms);
840 const EVENT_LIMIT: u32 = 100;
841 let mut event_counter = 0;
842
843 while let Ok(event) = saito.receiver_for_router.try_recv() {
844 let _result = saito.routing_thread.process_event(event).await;
845 event_counter += 1;
846 if event_counter >= EVENT_LIMIT {
847 break;
848 }
849 if !saito.routing_thread.is_ready_to_process() {
850 break;
851 }
852 }
853
854 saito.routing_thread.process_timer_event(duration).await;
855
856 event_counter = 0;
857 while let Ok(event) = saito.receiver_for_consensus.try_recv() {
858 let _result = saito.consensus_thread.process_event(event).await;
859 event_counter += 1;
860 if event_counter >= EVENT_LIMIT {
861 break;
862 }
863 if !saito.consensus_thread.is_ready_to_process() {
864 break;
865 }
866 }
867
868 saito.consensus_thread.process_timer_event(duration).await;
869
870 event_counter = 0;
871 while let Ok(event) = saito.receiver_for_verification.try_recv() {
872 let _result = saito.verification_thread.process_event(event).await;
873 event_counter += 1;
874 if event_counter >= EVENT_LIMIT {
875 break;
876 }
877 if !saito.verification_thread.is_ready_to_process() {
878 break;
879 }
880 }
881
882 saito
883 .verification_thread
884 .process_timer_event(duration)
885 .await;
886
887 event_counter = 0;
888 while let Ok(event) = saito.receiver_for_miner.try_recv() {
889 let _result = saito.mining_thread.process_event(event).await;
890 event_counter += 1;
891 if event_counter >= EVENT_LIMIT {
892 break;
893 }
894 if !saito.mining_thread.is_ready_to_process() {
895 break;
896 }
897 }
898
899 saito.mining_thread.process_timer_event(duration).await;
900
901 saito.stat_thread.process_timer_event(duration).await;
902
903 event_counter = 0;
904 while let Ok(event) = saito.receiver_for_stats.try_recv() {
905 let _result = saito.stat_thread.process_event(event).await;
906 event_counter += 1;
907 if event_counter >= EVENT_LIMIT {
908 break;
909 }
910 if !saito.stat_thread.is_ready_to_process() {
911 break;
912 }
913 }
914}
915
916#[wasm_bindgen]
917pub async fn process_stat_interval(current_time: Timestamp) {
918 let mut saito = SAITO.lock().await;
919
920 saito
921 .as_mut()
922 .unwrap()
923 .routing_thread
924 .on_stat_interval(current_time)
925 .await;
926
927 saito
928 .as_mut()
929 .unwrap()
930 .consensus_thread
931 .on_stat_interval(current_time)
932 .await;
933
934 saito
935 .as_mut()
936 .unwrap()
937 .verification_thread
938 .on_stat_interval(current_time)
939 .await;
940
941 saito
942 .as_mut()
943 .unwrap()
944 .mining_thread
945 .on_stat_interval(current_time)
946 .await;
947}
948
949#[wasm_bindgen]
950pub fn hash(buffer: Uint8Array) -> JsString {
951 let buffer: Vec<u8> = buffer.to_vec();
952 let hash = saito_core::core::util::crypto::hash(&buffer);
953 let str = hash.to_hex();
954 let str: js_sys::JsString = str.into();
955 str
956}
957
958#[wasm_bindgen]
959pub fn sign_buffer(buffer: Uint8Array, private_key: JsString) -> Result<JsString, JsValue> {
960 let buffer = buffer.to_vec();
961 let key = string_to_hex(private_key).or(Err(JsValue::from(
962 "Failed parsing private key string to key",
963 )))?;
964 let result = sign(&buffer, &key);
965
966 let signature = result.to_hex();
967 Ok(signature.into())
968}
969
970#[wasm_bindgen]
971pub fn verify_signature(buffer: Uint8Array, signature: JsString, public_key: JsString) -> bool {
972 let sig = string_to_hex(signature);
973 if sig.is_err() {
974 error!("signature is invalid");
975 return false;
976 }
977 let sig = sig.unwrap();
978 let key = string_to_key(public_key);
979 if key.is_err() {
980 error!(
981 "failed parsing public key from string. {:?}",
982 key.err().unwrap()
983 );
984 return false;
985 }
986 let buffer = buffer.to_vec();
987 let h = saito_core::core::util::crypto::hash(&buffer);
988 saito_core::core::util::crypto::verify_signature(&h, &sig, &key.unwrap())
989}
990
991#[wasm_bindgen]
992pub async fn get_peers() -> Array {
993 let saito = SAITO.lock().await;
994 let peers = saito
995 .as_ref()
996 .unwrap()
997 .routing_thread
998 .network
999 .peer_lock
1000 .read()
1001 .await;
1002 let valid_peer_count = peers
1003 .index_to_peers
1004 .iter()
1005 .filter(|(_index, peer)| peer.get_public_key().is_some())
1006 .count();
1007 let array = Array::new_with_length(valid_peer_count as u32);
1008 let mut array_index = 0;
1009 for (_i, (_peer_index, peer)) in peers.index_to_peers.iter().enumerate() {
1010 if peer.get_public_key().is_none() {
1011 continue;
1012 }
1013 let peer = peer.clone();
1014 array.set(
1015 array_index as u32,
1016 JsValue::from(WasmPeer::new_from_peer(peer)),
1017 );
1018 array_index += 1;
1019 }
1020 array
1021}
1022
1023#[wasm_bindgen]
1024pub async fn get_peer(peer_index: u64) -> Option<WasmPeer> {
1025 let saito = SAITO.lock().await;
1026 let peers = saito
1027 .as_ref()
1028 .unwrap()
1029 .routing_thread
1030 .network
1031 .peer_lock
1032 .read()
1033 .await;
1034 let peer = peers.find_peer_by_index(peer_index);
1035 if peer.is_none() || peer.unwrap().get_public_key().is_none() {
1036 warn!("peer not found");
1037 return None;
1038 }
1039 let peer = peer.cloned().unwrap();
1040 Some(WasmPeer::new_from_peer(peer))
1041}
1042
1043#[wasm_bindgen]
1044pub async fn get_account_slips(public_key: JsString) -> Result<Array, JsValue> {
1045 let saito = SAITO.lock().await;
1046 let blockchain = saito
1047 .as_ref()
1048 .unwrap()
1049 .routing_thread
1050 .blockchain_lock
1051 .read()
1052 .await;
1053 let key = string_to_key(public_key).or(Err(JsValue::from(
1054 "Failed parsing public key string to key",
1055 )))?;
1056 let mut slips = blockchain.get_slips_for(key);
1057 let array = js_sys::Array::new_with_length(slips.len() as u32);
1058
1059 for (index, slip) in slips.drain(..).enumerate() {
1060 let wasm_slip = WasmSlip::new_from_slip(slip);
1061 array.set(index as u32, JsValue::from(wasm_slip));
1062 }
1063
1064 Ok(array)
1065}
1066
1067#[wasm_bindgen]
1068pub async fn get_balance_snapshot(keys: js_sys::Array) -> WasmBalanceSnapshot {
1069 let saito = SAITO.lock().await;
1070 let config_lock = saito.as_ref().unwrap().routing_thread.config_lock.clone();
1071 let configs = config_lock.read().await;
1072 let keys: Vec<SaitoPublicKey> = string_array_to_base58_keys(keys);
1073
1074 let blockchain = saito
1075 .as_ref()
1076 .unwrap()
1077 .routing_thread
1078 .blockchain_lock
1079 .read()
1080 .await;
1081 let snapshot = blockchain.get_balance_snapshot(keys, configs.deref());
1082
1083 WasmBalanceSnapshot::new(snapshot)
1084}
1085
1086#[wasm_bindgen]
1087pub async fn update_from_balance_snapshot(snapshot: WasmBalanceSnapshot) {
1088 let saito = SAITO.lock().await;
1089 let mut wallet = saito
1090 .as_ref()
1091 .unwrap()
1092 .routing_thread
1093 .wallet_lock
1094 .write()
1095 .await;
1096 wallet.update_from_balance_snapshot(
1097 snapshot.get_snapshot(),
1098 Some(&saito.as_ref().unwrap().routing_thread.network),
1099 );
1100}
1101
1102#[wasm_bindgen]
1103pub fn generate_private_key() -> JsString {
1104 info!("generate_private_key");
1105 let (_, private_key) = generate_keys_wasm();
1106 private_key.to_hex().into()
1107}
1108
1109#[wasm_bindgen]
1110pub fn generate_public_key(private_key: JsString) -> Result<JsString, JsValue> {
1111 info!("generate_public_key");
1112 let private_key: SaitoPrivateKey = string_to_hex(private_key).or(Err(JsValue::from(
1113 "Failed parsing private key string to key",
1114 )))?;
1115 let (public_key, _) = generate_keypair_from_private_key(&private_key);
1116 Ok(public_key.to_base58().into())
1117}
1118
1119#[wasm_bindgen]
1120pub async fn propagate_transaction(tx: &WasmTransaction) {
1121 trace!("propagate_transaction");
1122
1123 let mut saito = SAITO.lock().await;
1124 let mut tx = tx.clone().tx;
1125 {
1126 let wallet = saito
1127 .as_ref()
1128 .unwrap()
1129 .routing_thread
1130 .wallet_lock
1131 .read()
1132 .await;
1133 tx.generate(&wallet.public_key, 0, 0);
1134 }
1135 saito
1136 .as_mut()
1137 .unwrap()
1138 .consensus_thread
1139 .process_event(ConsensusEvent::NewTransaction { transaction: tx })
1140 .await;
1141}
1142
1143#[wasm_bindgen]
1144pub async fn send_api_call(buffer: Uint8Array, msg_index: u32, peer_index: PeerIndex) {
1145 trace!("send_api_call : {:?}", peer_index);
1146 let saito = SAITO.lock().await;
1147 let api_message = ApiMessage {
1148 msg_index,
1149 data: buffer.to_vec(),
1150 };
1151 let message = Message::ApplicationMessage(api_message);
1152 let buffer = message.serialize();
1153 if peer_index == 0 {
1154 saito
1155 .as_ref()
1156 .unwrap()
1157 .routing_thread
1158 .network
1159 .io_interface
1160 .send_message_to_all(buffer.as_slice(), vec![])
1161 .await
1162 .unwrap();
1163 } else {
1164 saito
1165 .as_ref()
1166 .unwrap()
1167 .routing_thread
1168 .network
1169 .io_interface
1170 .send_message(peer_index, buffer.as_slice())
1171 .await
1172 .unwrap();
1173 }
1174}
1175
1176#[wasm_bindgen]
1177pub async fn send_api_success(buffer: Uint8Array, msg_index: u32, peer_index: PeerIndex) {
1178 trace!("send_api_success : {:?}", peer_index);
1179 let saito = SAITO.lock().await;
1180 let api_message = ApiMessage {
1181 msg_index,
1182 data: buffer.to_vec(),
1183 };
1184 let message = Message::Result(api_message);
1185 let buffer = message.serialize();
1186
1187 saito
1188 .as_ref()
1189 .unwrap()
1190 .routing_thread
1191 .network
1192 .io_interface
1193 .send_message(peer_index, buffer.as_slice())
1194 .await
1195 .unwrap();
1196}
1197
1198#[wasm_bindgen]
1199pub async fn send_api_error(buffer: Uint8Array, msg_index: u32, peer_index: PeerIndex) {
1200 trace!("send_api_error : {:?}", peer_index);
1201 let saito = SAITO.lock().await;
1202 let api_message = ApiMessage {
1203 msg_index,
1204 data: buffer.to_vec(),
1205 };
1206 let message = Message::Error(api_message);
1207 let buffer = message.serialize();
1208
1209 saito
1210 .as_ref()
1211 .unwrap()
1212 .routing_thread
1213 .network
1214 .io_interface
1215 .send_message(peer_index, buffer.as_slice())
1216 .await
1217 .unwrap();
1218}
1219
1220#[wasm_bindgen]
1221pub async fn get_wallet() -> WasmWallet {
1222 let saito = SAITO.lock().await;
1223 return saito.as_ref().unwrap().wallet.clone();
1224}
1225
1226#[wasm_bindgen]
1227pub async fn get_blockchain() -> WasmBlockchain {
1228 let saito = SAITO.lock().await;
1229 saito.as_ref().unwrap().blockchain.clone()
1230}
1231
1232#[wasm_bindgen]
1233pub async fn get_mempool_txs() -> js_sys::Array {
1234 let saito = SAITO.lock().await;
1235 let mempool = saito
1236 .as_ref()
1237 .unwrap()
1238 .consensus_thread
1239 .mempool_lock
1240 .read()
1241 .await;
1242 let txs = js_sys::Array::new_with_length(mempool.transactions.len() as u32);
1243 for (index, (_, tx)) in mempool.transactions.iter().enumerate() {
1244 let wasm_tx = WasmTransaction::from_transaction(tx.clone());
1245 txs.set(index as u32, JsValue::from(wasm_tx));
1246 }
1247
1248 txs
1249}
1250
1251#[wasm_bindgen]
1252pub async fn set_wallet_version(major: u8, minor: u8, patch: u16) {
1253 let saito = SAITO.lock().await;
1254 let mut wallet = saito.as_ref().unwrap().wallet.wallet.write().await;
1255 wallet.wallet_version = Version {
1256 major,
1257 minor,
1258 patch,
1259 };
1260}
1261
1262#[wasm_bindgen]
1263pub fn is_valid_public_key(key: JsString) -> bool {
1264 let result = string_to_key(key);
1265 if result.is_err() {
1266 return false;
1267 }
1268 let key: SaitoPublicKey = result.unwrap();
1269 saito_core::core::util::crypto::is_valid_public_key(&key)
1270}
1271
1272#[wasm_bindgen]
1273pub async fn write_issuance_file(threshold: Currency) {
1274 let mut saito = SAITO.lock().await;
1275 let _configs_lock = saito.as_mut().unwrap().routing_thread.config_lock.clone();
1276 let _mempool_lock = saito.as_mut().unwrap().routing_thread.mempool_lock.clone();
1277 let blockchain_lock = saito
1278 .as_mut()
1279 .unwrap()
1280 .routing_thread
1281 .blockchain_lock
1282 .clone();
1283 let mut storage = &mut saito.as_mut().unwrap().consensus_thread.storage;
1284 let blockchain = blockchain_lock.write().await;
1287 blockchain
1288 .write_issuance_file(threshold, "./data/issuance.file", &mut storage)
1289 .await;
1290}
1291
1292#[wasm_bindgen]
1293pub async fn disable_producing_blocks_by_timer() {
1294 let mut saito = SAITO.lock().await;
1295 saito
1296 .as_mut()
1297 .unwrap()
1298 .consensus_thread
1299 .produce_blocks_by_timer = false;
1300 }
1302#[wasm_bindgen]
1303pub async fn produce_block_with_gt() -> bool {
1304 let mut saito = SAITO.lock().await;
1305
1306 let config_lock = saito.as_ref().unwrap().routing_thread.config_lock.clone();
1307 let blockchain_lock = saito.as_ref().unwrap().blockchain.blockchain_lock.clone();
1308 let mempool_lock = saito
1309 .as_ref()
1310 .unwrap()
1311 .consensus_thread
1312 .mempool_lock
1313 .clone();
1314 let wallet_lock = saito.as_ref().unwrap().wallet.wallet.clone();
1315
1316 let configs = config_lock.read().await;
1317 let blockchain = blockchain_lock.read().await;
1318
1319 let genesis_period = configs.get_consensus_config().unwrap().genesis_period;
1320 let latest_block_id = blockchain.get_latest_block_id();
1321
1322 let mut mempool = mempool_lock.write().await;
1323 let public_key;
1324 let private_key;
1325 {
1326 let wallet = wallet_lock.read().await;
1327 public_key = wallet.public_key;
1328 private_key = wallet.private_key;
1329 }
1330
1331 let gt_tx: Transaction;
1332
1333 {
1334 let miner = &mut saito.as_mut().unwrap().mining_thread;
1335 if miner.target == [0; 32] {
1336 let blockchain = blockchain_lock.read().await;
1337 if let Some(block) = blockchain.get_latest_block() {
1338 miner.difficulty = block.difficulty;
1339 miner.target = block.hash;
1340 miner.target_id = block.id;
1341 } else {
1342 warn!("couldn't find the latest block");
1343 }
1344 }
1345 info!("mining for a gt. target : {:?}", miner.target.to_hex());
1346
1347 loop {
1348 if let Some(gt) = miner.mine().await {
1349 info!("gt found : {:?}", gt.target.to_hex());
1350
1351 let transaction =
1352 Wallet::create_golden_ticket_transaction(gt, &public_key, &private_key).await;
1353
1354 gt_tx = transaction;
1355 break;
1356 }
1357 }
1358 }
1359
1360 {
1361 let mut wallet = wallet_lock.write().await;
1362 if let Ok(mut tx) = Transaction::create(
1363 &mut wallet,
1364 public_key,
1365 0,
1366 0,
1367 false,
1368 None,
1369 latest_block_id,
1370 genesis_period,
1371 ) {
1372 drop(wallet);
1373 info!("created tx");
1374 tx.transaction_type = TransactionType::Vip;
1375 tx.sign(&private_key);
1376 info!("tx signed");
1377 mempool.add_transaction_if_validates(tx, &blockchain).await;
1378 info!("Tx added to mempool");
1379 }
1380 }
1381
1382 let timestamp = saito
1383 .as_ref()
1384 .unwrap()
1385 .consensus_thread
1386 .timer
1387 .get_timestamp_in_ms();
1388
1389 info!("waiting till a block is produced");
1390 for _ in 0..1000 {
1391 if let Some(block) = saito
1392 .as_mut()
1393 .unwrap()
1394 .consensus_thread
1395 .produce_block(
1396 timestamp,
1397 Some(>_tx),
1398 mempool.deref_mut(),
1399 blockchain.deref(),
1400 configs.deref(),
1401 )
1402 .await
1403 {
1404 info!("produced block with gt");
1405 drop(mempool);
1406 drop(blockchain);
1407 drop(configs);
1408 saito
1409 .as_mut()
1410 .unwrap()
1411 .consensus_thread
1412 .process_event(ConsensusEvent::BlockFetched {
1413 peer_index: 0,
1414 block,
1415 })
1416 .await;
1417 return true;
1418 }
1419 }
1420 warn!("couldn't produce block");
1421 false
1422}
1423
1424#[wasm_bindgen]
1425pub async fn produce_block_without_gt() -> bool {
1426 let mut saito = SAITO.lock().await;
1427
1428 let config_lock = saito.as_ref().unwrap().routing_thread.config_lock.clone();
1429 let blockchain_lock = saito.as_ref().unwrap().blockchain.blockchain_lock.clone();
1430 let mempool_lock = saito
1431 .as_ref()
1432 .unwrap()
1433 .consensus_thread
1434 .mempool_lock
1435 .clone();
1436 let wallet_lock = saito.as_ref().unwrap().wallet.wallet.clone();
1437
1438 let configs = config_lock.read().await;
1439 let blockchain = blockchain_lock.read().await;
1440
1441 let genesis_period = configs.get_consensus_config().unwrap().genesis_period;
1442 let latest_block_id = blockchain.get_latest_block_id();
1443
1444 let mut mempool = mempool_lock.write().await;
1445 let public_key;
1446 let private_key;
1447 {
1448 let wallet = wallet_lock.read().await;
1449 public_key = wallet.public_key;
1450 private_key = wallet.private_key;
1451 }
1452 {
1453 info!(
1454 "clearing {:?} gts from mempool...",
1455 mempool.golden_tickets.len()
1456 );
1457 mempool.golden_tickets.clear();
1458 }
1459 {
1460 let mut wallet = wallet_lock.write().await;
1461 if let Ok(mut tx) = Transaction::create(
1462 &mut wallet,
1463 public_key,
1464 0,
1465 0,
1466 false,
1467 None,
1468 latest_block_id,
1469 genesis_period,
1470 ) {
1471 drop(wallet);
1472 info!("created tx");
1473 tx.transaction_type = TransactionType::Vip;
1474 tx.sign(&private_key);
1475 info!("tx signed");
1476 mempool.add_transaction_if_validates(tx, &blockchain).await;
1477 info!("Tx added to mempool");
1478 }
1479 }
1480
1481 let timestamp = saito
1482 .as_ref()
1483 .unwrap()
1484 .consensus_thread
1485 .timer
1486 .get_timestamp_in_ms();
1487
1488 info!("waiting till a block is produced");
1489 for _ in 0..1000 {
1490 if let Some(block) = saito
1491 .as_mut()
1492 .unwrap()
1493 .consensus_thread
1494 .produce_block(
1495 timestamp,
1496 None,
1497 mempool.deref_mut(),
1498 blockchain.deref(),
1499 configs.deref(),
1500 )
1501 .await
1502 {
1503 info!("produced block with gt");
1504 drop(mempool);
1505 drop(blockchain);
1506 drop(configs);
1507 saito
1508 .as_mut()
1509 .unwrap()
1510 .consensus_thread
1511 .process_event(ConsensusEvent::BlockFetched {
1512 peer_index: 0,
1513 block,
1514 })
1515 .await;
1516 return true;
1517 }
1518 }
1519 warn!("couldn't produce block");
1520 false
1521}
1522
1523pub fn generate_keys_wasm() -> (SaitoPublicKey, SaitoPrivateKey) {
1524 let (mut secret_key, mut public_key) =
1525 SECP256K1.generate_keypair(&mut rand::rngs::OsRng::default());
1526 while public_key.serialize().to_base58().len() != 44 {
1527 let keypair_tuple = SECP256K1.generate_keypair(&mut rand::rngs::OsRng::default());
1529 secret_key = keypair_tuple.0;
1530 public_key = keypair_tuple.1;
1531 }
1532 let mut secret_bytes = [0u8; 32];
1533 for i in 0..32 {
1534 secret_bytes[i] = secret_key[i];
1535 }
1536 (public_key.serialize(), secret_bytes)
1537}
1538
1539pub fn string_to_key<T: TryFrom<Vec<u8>> + PrintForLog<T>>(key: JsString) -> Result<T, Error>
1540where
1541 <T as TryFrom<Vec<u8>>>::Error: std::fmt::Debug,
1542{
1543 let str = key.as_string();
1544 if str.is_none() {
1545 error!("cannot convert wasm string to rust string");
1546 return Err(Error::from(ErrorKind::InvalidInput));
1547 }
1548
1549 let str = str.unwrap();
1550 if str.is_empty() {
1551 return Err(Error::from(ErrorKind::InvalidInput));
1553 }
1554
1555 let key = T::from_base58(str.as_str());
1556 if key.is_err() {
1557 return Err(Error::from(ErrorKind::InvalidInput));
1563 }
1564 let key = key.unwrap();
1565 Ok(key)
1566}
1567
1568pub fn string_to_hex<T: TryFrom<Vec<u8>> + PrintForLog<T>>(key: JsString) -> Result<T, Error>
1569where
1570 <T as TryFrom<Vec<u8>>>::Error: std::fmt::Debug,
1571{
1572 let str = key.as_string();
1573 if str.is_none() {
1574 return Err(Error::from(ErrorKind::InvalidInput));
1576 }
1577
1578 let str = str.unwrap();
1579 if str.is_empty() {
1580 debug!("cannot convert empty string to hex");
1581 return Err(Error::from(ErrorKind::InvalidInput));
1582 }
1583
1584 let key = T::from_hex(str.as_str());
1585 if key.is_err() {
1586 error!(
1587 "failed parsing hex : {:?}. str : {:?}",
1588 key.err().unwrap(),
1589 str
1590 );
1591 return Err(Error::from(ErrorKind::InvalidInput));
1592 }
1593 let key = key.unwrap();
1594 Ok(key)
1595}
1596
1597pub fn string_array_to_base58_keys<T: TryFrom<Vec<u8>> + PrintForLog<T>>(
1598 array: js_sys::Array,
1599) -> Vec<T> {
1600 let array: Vec<T> = array
1601 .to_vec()
1602 .drain(..)
1603 .filter_map(|key| {
1604 let key: String = key.as_string()?;
1605 let key = T::from_base58(key.as_str());
1606 if key.is_err() {
1607 return None;
1608 }
1609 let key: T = key.unwrap();
1610 Some(key)
1611 })
1612 .collect();
1613 array
1614}
1615
1616